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, SaveOptions},
  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    hide_task: Option<Task<()>>,
  903    popover_bounds: Option<Bounds<Pixels>>,
  904    popover_state: InlineBlamePopoverState,
  905}
  906
  907enum SelectionDragState {
  908    /// State when no drag related activity is detected.
  909    None,
  910    /// State when the mouse is down on a selection that is about to be dragged.
  911    ReadyToDrag {
  912        selection: Selection<Anchor>,
  913        click_position: gpui::Point<Pixels>,
  914        mouse_down_time: Instant,
  915    },
  916    /// State when the mouse is dragging the selection in the editor.
  917    Dragging {
  918        selection: Selection<Anchor>,
  919        drop_cursor: Selection<Anchor>,
  920        hide_drop_cursor: bool,
  921    },
  922}
  923
  924/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  925/// a breakpoint on them.
  926#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  927struct PhantomBreakpointIndicator {
  928    display_row: DisplayRow,
  929    /// There's a small debounce between hovering over the line and showing the indicator.
  930    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  931    is_active: bool,
  932    collides_with_existing_breakpoint: bool,
  933}
  934
  935/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  936///
  937/// See the [module level documentation](self) for more information.
  938pub struct Editor {
  939    focus_handle: FocusHandle,
  940    last_focused_descendant: Option<WeakFocusHandle>,
  941    /// The text buffer being edited
  942    buffer: Entity<MultiBuffer>,
  943    /// Map of how text in the buffer should be displayed.
  944    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  945    pub display_map: Entity<DisplayMap>,
  946    pub selections: SelectionsCollection,
  947    pub scroll_manager: ScrollManager,
  948    /// When inline assist editors are linked, they all render cursors because
  949    /// typing enters text into each of them, even the ones that aren't focused.
  950    pub(crate) show_cursor_when_unfocused: bool,
  951    columnar_selection_tail: Option<Anchor>,
  952    columnar_display_point: Option<DisplayPoint>,
  953    add_selections_state: Option<AddSelectionsState>,
  954    select_next_state: Option<SelectNextState>,
  955    select_prev_state: Option<SelectNextState>,
  956    selection_history: SelectionHistory,
  957    defer_selection_effects: bool,
  958    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  959    autoclose_regions: Vec<AutocloseRegion>,
  960    snippet_stack: InvalidationStack<SnippetState>,
  961    select_syntax_node_history: SelectSyntaxNodeHistory,
  962    ime_transaction: Option<TransactionId>,
  963    pub diagnostics_max_severity: DiagnosticSeverity,
  964    active_diagnostics: ActiveDiagnostic,
  965    show_inline_diagnostics: bool,
  966    inline_diagnostics_update: Task<()>,
  967    inline_diagnostics_enabled: bool,
  968    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  969    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  970    hard_wrap: Option<usize>,
  971
  972    // TODO: make this a access method
  973    pub project: Option<Entity<Project>>,
  974    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  975    completion_provider: Option<Rc<dyn CompletionProvider>>,
  976    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  977    blink_manager: Entity<BlinkManager>,
  978    show_cursor_names: bool,
  979    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  980    pub show_local_selections: bool,
  981    mode: EditorMode,
  982    show_breadcrumbs: bool,
  983    show_gutter: bool,
  984    show_scrollbars: ScrollbarAxes,
  985    minimap_visibility: MinimapVisibility,
  986    offset_content: bool,
  987    disable_expand_excerpt_buttons: bool,
  988    show_line_numbers: Option<bool>,
  989    use_relative_line_numbers: Option<bool>,
  990    show_git_diff_gutter: Option<bool>,
  991    show_code_actions: Option<bool>,
  992    show_runnables: Option<bool>,
  993    show_breakpoints: Option<bool>,
  994    show_wrap_guides: Option<bool>,
  995    show_indent_guides: Option<bool>,
  996    placeholder_text: Option<Arc<str>>,
  997    highlight_order: usize,
  998    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  999    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1000    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1001    scrollbar_marker_state: ScrollbarMarkerState,
 1002    active_indent_guides_state: ActiveIndentGuidesState,
 1003    nav_history: Option<ItemNavHistory>,
 1004    context_menu: RefCell<Option<CodeContextMenu>>,
 1005    context_menu_options: Option<ContextMenuOptions>,
 1006    mouse_context_menu: Option<MouseContextMenu>,
 1007    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1008    inline_blame_popover: Option<InlineBlamePopover>,
 1009    inline_blame_popover_show_task: Option<Task<()>>,
 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
 1225#[derive(Debug)]
 1226pub struct SelectionEffects {
 1227    nav_history: bool,
 1228    completions: bool,
 1229    scroll: Option<Autoscroll>,
 1230}
 1231
 1232impl Default for SelectionEffects {
 1233    fn default() -> Self {
 1234        Self {
 1235            nav_history: true,
 1236            completions: true,
 1237            scroll: Some(Autoscroll::fit()),
 1238        }
 1239    }
 1240}
 1241impl SelectionEffects {
 1242    pub fn scroll(scroll: Autoscroll) -> Self {
 1243        Self {
 1244            scroll: Some(scroll),
 1245            ..Default::default()
 1246        }
 1247    }
 1248
 1249    pub fn no_scroll() -> Self {
 1250        Self {
 1251            scroll: None,
 1252            ..Default::default()
 1253        }
 1254    }
 1255
 1256    pub fn completions(self, completions: bool) -> Self {
 1257        Self {
 1258            completions,
 1259            ..self
 1260        }
 1261    }
 1262
 1263    pub fn nav_history(self, nav_history: bool) -> Self {
 1264        Self {
 1265            nav_history,
 1266            ..self
 1267        }
 1268    }
 1269}
 1270
 1271struct DeferredSelectionEffectsState {
 1272    changed: bool,
 1273    effects: SelectionEffects,
 1274    old_cursor_position: Anchor,
 1275    history_entry: SelectionHistoryEntry,
 1276}
 1277
 1278#[derive(Default)]
 1279struct SelectionHistory {
 1280    #[allow(clippy::type_complexity)]
 1281    selections_by_transaction:
 1282        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1283    mode: SelectionHistoryMode,
 1284    undo_stack: VecDeque<SelectionHistoryEntry>,
 1285    redo_stack: VecDeque<SelectionHistoryEntry>,
 1286}
 1287
 1288impl SelectionHistory {
 1289    #[track_caller]
 1290    fn insert_transaction(
 1291        &mut self,
 1292        transaction_id: TransactionId,
 1293        selections: Arc<[Selection<Anchor>]>,
 1294    ) {
 1295        if selections.is_empty() {
 1296            log::error!(
 1297                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1298                std::panic::Location::caller()
 1299            );
 1300            return;
 1301        }
 1302        self.selections_by_transaction
 1303            .insert(transaction_id, (selections, None));
 1304    }
 1305
 1306    #[allow(clippy::type_complexity)]
 1307    fn transaction(
 1308        &self,
 1309        transaction_id: TransactionId,
 1310    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1311        self.selections_by_transaction.get(&transaction_id)
 1312    }
 1313
 1314    #[allow(clippy::type_complexity)]
 1315    fn transaction_mut(
 1316        &mut self,
 1317        transaction_id: TransactionId,
 1318    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1319        self.selections_by_transaction.get_mut(&transaction_id)
 1320    }
 1321
 1322    fn push(&mut self, entry: SelectionHistoryEntry) {
 1323        if !entry.selections.is_empty() {
 1324            match self.mode {
 1325                SelectionHistoryMode::Normal => {
 1326                    self.push_undo(entry);
 1327                    self.redo_stack.clear();
 1328                }
 1329                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1330                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1331                SelectionHistoryMode::Skipping => {}
 1332            }
 1333        }
 1334    }
 1335
 1336    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1337        if self
 1338            .undo_stack
 1339            .back()
 1340            .map_or(true, |e| e.selections != entry.selections)
 1341        {
 1342            self.undo_stack.push_back(entry);
 1343            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1344                self.undo_stack.pop_front();
 1345            }
 1346        }
 1347    }
 1348
 1349    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1350        if self
 1351            .redo_stack
 1352            .back()
 1353            .map_or(true, |e| e.selections != entry.selections)
 1354        {
 1355            self.redo_stack.push_back(entry);
 1356            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1357                self.redo_stack.pop_front();
 1358            }
 1359        }
 1360    }
 1361}
 1362
 1363#[derive(Clone, Copy)]
 1364pub struct RowHighlightOptions {
 1365    pub autoscroll: bool,
 1366    pub include_gutter: bool,
 1367}
 1368
 1369impl Default for RowHighlightOptions {
 1370    fn default() -> Self {
 1371        Self {
 1372            autoscroll: Default::default(),
 1373            include_gutter: true,
 1374        }
 1375    }
 1376}
 1377
 1378struct RowHighlight {
 1379    index: usize,
 1380    range: Range<Anchor>,
 1381    color: Hsla,
 1382    options: RowHighlightOptions,
 1383    type_id: TypeId,
 1384}
 1385
 1386#[derive(Clone, Debug)]
 1387struct AddSelectionsState {
 1388    groups: Vec<AddSelectionsGroup>,
 1389}
 1390
 1391#[derive(Clone, Debug)]
 1392struct AddSelectionsGroup {
 1393    above: bool,
 1394    stack: Vec<usize>,
 1395}
 1396
 1397#[derive(Clone)]
 1398struct SelectNextState {
 1399    query: AhoCorasick,
 1400    wordwise: bool,
 1401    done: bool,
 1402}
 1403
 1404impl std::fmt::Debug for SelectNextState {
 1405    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1406        f.debug_struct(std::any::type_name::<Self>())
 1407            .field("wordwise", &self.wordwise)
 1408            .field("done", &self.done)
 1409            .finish()
 1410    }
 1411}
 1412
 1413#[derive(Debug)]
 1414struct AutocloseRegion {
 1415    selection_id: usize,
 1416    range: Range<Anchor>,
 1417    pair: BracketPair,
 1418}
 1419
 1420#[derive(Debug)]
 1421struct SnippetState {
 1422    ranges: Vec<Vec<Range<Anchor>>>,
 1423    active_index: usize,
 1424    choices: Vec<Option<Vec<String>>>,
 1425}
 1426
 1427#[doc(hidden)]
 1428pub struct RenameState {
 1429    pub range: Range<Anchor>,
 1430    pub old_name: Arc<str>,
 1431    pub editor: Entity<Editor>,
 1432    block_id: CustomBlockId,
 1433}
 1434
 1435struct InvalidationStack<T>(Vec<T>);
 1436
 1437struct RegisteredInlineCompletionProvider {
 1438    provider: Arc<dyn InlineCompletionProviderHandle>,
 1439    _subscription: Subscription,
 1440}
 1441
 1442#[derive(Debug, PartialEq, Eq)]
 1443pub struct ActiveDiagnosticGroup {
 1444    pub active_range: Range<Anchor>,
 1445    pub active_message: String,
 1446    pub group_id: usize,
 1447    pub blocks: HashSet<CustomBlockId>,
 1448}
 1449
 1450#[derive(Debug, PartialEq, Eq)]
 1451
 1452pub(crate) enum ActiveDiagnostic {
 1453    None,
 1454    All,
 1455    Group(ActiveDiagnosticGroup),
 1456}
 1457
 1458#[derive(Serialize, Deserialize, Clone, Debug)]
 1459pub struct ClipboardSelection {
 1460    /// The number of bytes in this selection.
 1461    pub len: usize,
 1462    /// Whether this was a full-line selection.
 1463    pub is_entire_line: bool,
 1464    /// The indentation of the first line when this content was originally copied.
 1465    pub first_line_indent: u32,
 1466}
 1467
 1468// selections, scroll behavior, was newest selection reversed
 1469type SelectSyntaxNodeHistoryState = (
 1470    Box<[Selection<usize>]>,
 1471    SelectSyntaxNodeScrollBehavior,
 1472    bool,
 1473);
 1474
 1475#[derive(Default)]
 1476struct SelectSyntaxNodeHistory {
 1477    stack: Vec<SelectSyntaxNodeHistoryState>,
 1478    // disable temporarily to allow changing selections without losing the stack
 1479    pub disable_clearing: bool,
 1480}
 1481
 1482impl SelectSyntaxNodeHistory {
 1483    pub fn try_clear(&mut self) {
 1484        if !self.disable_clearing {
 1485            self.stack.clear();
 1486        }
 1487    }
 1488
 1489    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1490        self.stack.push(selection);
 1491    }
 1492
 1493    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1494        self.stack.pop()
 1495    }
 1496}
 1497
 1498enum SelectSyntaxNodeScrollBehavior {
 1499    CursorTop,
 1500    FitSelection,
 1501    CursorBottom,
 1502}
 1503
 1504#[derive(Debug)]
 1505pub(crate) struct NavigationData {
 1506    cursor_anchor: Anchor,
 1507    cursor_position: Point,
 1508    scroll_anchor: ScrollAnchor,
 1509    scroll_top_row: u32,
 1510}
 1511
 1512#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1513pub enum GotoDefinitionKind {
 1514    Symbol,
 1515    Declaration,
 1516    Type,
 1517    Implementation,
 1518}
 1519
 1520#[derive(Debug, Clone)]
 1521enum InlayHintRefreshReason {
 1522    ModifiersChanged(bool),
 1523    Toggle(bool),
 1524    SettingsChange(InlayHintSettings),
 1525    NewLinesShown,
 1526    BufferEdited(HashSet<Arc<Language>>),
 1527    RefreshRequested,
 1528    ExcerptsRemoved(Vec<ExcerptId>),
 1529}
 1530
 1531impl InlayHintRefreshReason {
 1532    fn description(&self) -> &'static str {
 1533        match self {
 1534            Self::ModifiersChanged(_) => "modifiers changed",
 1535            Self::Toggle(_) => "toggle",
 1536            Self::SettingsChange(_) => "settings change",
 1537            Self::NewLinesShown => "new lines shown",
 1538            Self::BufferEdited(_) => "buffer edited",
 1539            Self::RefreshRequested => "refresh requested",
 1540            Self::ExcerptsRemoved(_) => "excerpts removed",
 1541        }
 1542    }
 1543}
 1544
 1545pub enum FormatTarget {
 1546    Buffers(HashSet<Entity<Buffer>>),
 1547    Ranges(Vec<Range<MultiBufferPoint>>),
 1548}
 1549
 1550pub(crate) struct FocusedBlock {
 1551    id: BlockId,
 1552    focus_handle: WeakFocusHandle,
 1553}
 1554
 1555#[derive(Clone)]
 1556enum JumpData {
 1557    MultiBufferRow {
 1558        row: MultiBufferRow,
 1559        line_offset_from_top: u32,
 1560    },
 1561    MultiBufferPoint {
 1562        excerpt_id: ExcerptId,
 1563        position: Point,
 1564        anchor: text::Anchor,
 1565        line_offset_from_top: u32,
 1566    },
 1567}
 1568
 1569pub enum MultibufferSelectionMode {
 1570    First,
 1571    All,
 1572}
 1573
 1574#[derive(Clone, Copy, Debug, Default)]
 1575pub struct RewrapOptions {
 1576    pub override_language_settings: bool,
 1577    pub preserve_existing_whitespace: bool,
 1578}
 1579
 1580impl Editor {
 1581    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1582        let buffer = cx.new(|cx| Buffer::local("", cx));
 1583        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1584        Self::new(
 1585            EditorMode::SingleLine { auto_width: false },
 1586            buffer,
 1587            None,
 1588            window,
 1589            cx,
 1590        )
 1591    }
 1592
 1593    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1594        let buffer = cx.new(|cx| Buffer::local("", cx));
 1595        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1596        Self::new(EditorMode::full(), buffer, None, window, cx)
 1597    }
 1598
 1599    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1600        let buffer = cx.new(|cx| Buffer::local("", cx));
 1601        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1602        Self::new(
 1603            EditorMode::SingleLine { auto_width: true },
 1604            buffer,
 1605            None,
 1606            window,
 1607            cx,
 1608        )
 1609    }
 1610
 1611    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1612        let buffer = cx.new(|cx| Buffer::local("", cx));
 1613        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1614        Self::new(
 1615            EditorMode::AutoHeight { max_lines },
 1616            buffer,
 1617            None,
 1618            window,
 1619            cx,
 1620        )
 1621    }
 1622
 1623    pub fn for_buffer(
 1624        buffer: Entity<Buffer>,
 1625        project: Option<Entity<Project>>,
 1626        window: &mut Window,
 1627        cx: &mut Context<Self>,
 1628    ) -> Self {
 1629        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1630        Self::new(EditorMode::full(), buffer, project, window, cx)
 1631    }
 1632
 1633    pub fn for_multibuffer(
 1634        buffer: Entity<MultiBuffer>,
 1635        project: Option<Entity<Project>>,
 1636        window: &mut Window,
 1637        cx: &mut Context<Self>,
 1638    ) -> Self {
 1639        Self::new(EditorMode::full(), buffer, project, window, cx)
 1640    }
 1641
 1642    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1643        let mut clone = Self::new(
 1644            self.mode.clone(),
 1645            self.buffer.clone(),
 1646            self.project.clone(),
 1647            window,
 1648            cx,
 1649        );
 1650        self.display_map.update(cx, |display_map, cx| {
 1651            let snapshot = display_map.snapshot(cx);
 1652            clone.display_map.update(cx, |display_map, cx| {
 1653                display_map.set_state(&snapshot, cx);
 1654            });
 1655        });
 1656        clone.folds_did_change(cx);
 1657        clone.selections.clone_state(&self.selections);
 1658        clone.scroll_manager.clone_state(&self.scroll_manager);
 1659        clone.searchable = self.searchable;
 1660        clone.read_only = self.read_only;
 1661        clone
 1662    }
 1663
 1664    pub fn new(
 1665        mode: EditorMode,
 1666        buffer: Entity<MultiBuffer>,
 1667        project: Option<Entity<Project>>,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        Editor::new_internal(mode, buffer, project, None, window, cx)
 1672    }
 1673
 1674    fn new_internal(
 1675        mode: EditorMode,
 1676        buffer: Entity<MultiBuffer>,
 1677        project: Option<Entity<Project>>,
 1678        display_map: Option<Entity<DisplayMap>>,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        debug_assert!(
 1683            display_map.is_none() || mode.is_minimap(),
 1684            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1685        );
 1686
 1687        let full_mode = mode.is_full();
 1688        let diagnostics_max_severity = if full_mode {
 1689            EditorSettings::get_global(cx)
 1690                .diagnostics_max_severity
 1691                .unwrap_or(DiagnosticSeverity::Hint)
 1692        } else {
 1693            DiagnosticSeverity::Off
 1694        };
 1695        let style = window.text_style();
 1696        let font_size = style.font_size.to_pixels(window.rem_size());
 1697        let editor = cx.entity().downgrade();
 1698        let fold_placeholder = FoldPlaceholder {
 1699            constrain_width: true,
 1700            render: Arc::new(move |fold_id, fold_range, cx| {
 1701                let editor = editor.clone();
 1702                div()
 1703                    .id(fold_id)
 1704                    .bg(cx.theme().colors().ghost_element_background)
 1705                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1706                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1707                    .rounded_xs()
 1708                    .size_full()
 1709                    .cursor_pointer()
 1710                    .child("")
 1711                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1712                    .on_click(move |_, _window, cx| {
 1713                        editor
 1714                            .update(cx, |editor, cx| {
 1715                                editor.unfold_ranges(
 1716                                    &[fold_range.start..fold_range.end],
 1717                                    true,
 1718                                    false,
 1719                                    cx,
 1720                                );
 1721                                cx.stop_propagation();
 1722                            })
 1723                            .ok();
 1724                    })
 1725                    .into_any()
 1726            }),
 1727            merge_adjacent: true,
 1728            ..FoldPlaceholder::default()
 1729        };
 1730        let display_map = display_map.unwrap_or_else(|| {
 1731            cx.new(|cx| {
 1732                DisplayMap::new(
 1733                    buffer.clone(),
 1734                    style.font(),
 1735                    font_size,
 1736                    None,
 1737                    FILE_HEADER_HEIGHT,
 1738                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1739                    fold_placeholder,
 1740                    diagnostics_max_severity,
 1741                    cx,
 1742                )
 1743            })
 1744        });
 1745
 1746        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1747
 1748        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1749
 1750        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1751            .then(|| language_settings::SoftWrap::None);
 1752
 1753        let mut project_subscriptions = Vec::new();
 1754        if mode.is_full() {
 1755            if let Some(project) = project.as_ref() {
 1756                project_subscriptions.push(cx.subscribe_in(
 1757                    project,
 1758                    window,
 1759                    |editor, _, event, window, cx| match event {
 1760                        project::Event::RefreshCodeLens => {
 1761                            // we always query lens with actions, without storing them, always refreshing them
 1762                        }
 1763                        project::Event::RefreshInlayHints => {
 1764                            editor
 1765                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1766                        }
 1767                        project::Event::LanguageServerAdded(..)
 1768                        | project::Event::LanguageServerRemoved(..) => {
 1769                            if editor.tasks_update_task.is_none() {
 1770                                editor.tasks_update_task =
 1771                                    Some(editor.refresh_runnables(window, cx));
 1772                            }
 1773                            editor.pull_diagnostics(None, window, cx);
 1774                        }
 1775                        project::Event::SnippetEdit(id, snippet_edits) => {
 1776                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1777                                let focus_handle = editor.focus_handle(cx);
 1778                                if focus_handle.is_focused(window) {
 1779                                    let snapshot = buffer.read(cx).snapshot();
 1780                                    for (range, snippet) in snippet_edits {
 1781                                        let editor_range =
 1782                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1783                                        editor
 1784                                            .insert_snippet(
 1785                                                &[editor_range],
 1786                                                snippet.clone(),
 1787                                                window,
 1788                                                cx,
 1789                                            )
 1790                                            .ok();
 1791                                    }
 1792                                }
 1793                            }
 1794                        }
 1795                        _ => {}
 1796                    },
 1797                ));
 1798                if let Some(task_inventory) = project
 1799                    .read(cx)
 1800                    .task_store()
 1801                    .read(cx)
 1802                    .task_inventory()
 1803                    .cloned()
 1804                {
 1805                    project_subscriptions.push(cx.observe_in(
 1806                        &task_inventory,
 1807                        window,
 1808                        |editor, _, window, cx| {
 1809                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1810                        },
 1811                    ));
 1812                };
 1813
 1814                project_subscriptions.push(cx.subscribe_in(
 1815                    &project.read(cx).breakpoint_store(),
 1816                    window,
 1817                    |editor, _, event, window, cx| match event {
 1818                        BreakpointStoreEvent::ClearDebugLines => {
 1819                            editor.clear_row_highlights::<ActiveDebugLine>();
 1820                            editor.refresh_inline_values(cx);
 1821                        }
 1822                        BreakpointStoreEvent::SetDebugLine => {
 1823                            if editor.go_to_active_debug_line(window, cx) {
 1824                                cx.stop_propagation();
 1825                            }
 1826
 1827                            editor.refresh_inline_values(cx);
 1828                        }
 1829                        _ => {}
 1830                    },
 1831                ));
 1832            }
 1833        }
 1834
 1835        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1836
 1837        let inlay_hint_settings =
 1838            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1839        let focus_handle = cx.focus_handle();
 1840        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1841            .detach();
 1842        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1843            .detach();
 1844        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1845            .detach();
 1846        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1847            .detach();
 1848        cx.observe_pending_input(window, Self::observe_pending_input)
 1849            .detach();
 1850
 1851        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1852            Some(false)
 1853        } else {
 1854            None
 1855        };
 1856
 1857        let breakpoint_store = match (&mode, project.as_ref()) {
 1858            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1859            _ => None,
 1860        };
 1861
 1862        let mut code_action_providers = Vec::new();
 1863        let mut load_uncommitted_diff = None;
 1864        if let Some(project) = project.clone() {
 1865            load_uncommitted_diff = Some(
 1866                update_uncommitted_diff_for_buffer(
 1867                    cx.entity(),
 1868                    &project,
 1869                    buffer.read(cx).all_buffers(),
 1870                    buffer.clone(),
 1871                    cx,
 1872                )
 1873                .shared(),
 1874            );
 1875            code_action_providers.push(Rc::new(project) as Rc<_>);
 1876        }
 1877
 1878        let mut editor = Self {
 1879            focus_handle,
 1880            show_cursor_when_unfocused: false,
 1881            last_focused_descendant: None,
 1882            buffer: buffer.clone(),
 1883            display_map: display_map.clone(),
 1884            selections,
 1885            scroll_manager: ScrollManager::new(cx),
 1886            columnar_selection_tail: None,
 1887            columnar_display_point: None,
 1888            add_selections_state: None,
 1889            select_next_state: None,
 1890            select_prev_state: None,
 1891            selection_history: SelectionHistory::default(),
 1892            defer_selection_effects: false,
 1893            deferred_selection_effects_state: None,
 1894            autoclose_regions: Vec::new(),
 1895            snippet_stack: InvalidationStack::default(),
 1896            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1897            ime_transaction: None,
 1898            active_diagnostics: ActiveDiagnostic::None,
 1899            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1900            inline_diagnostics_update: Task::ready(()),
 1901            inline_diagnostics: Vec::new(),
 1902            soft_wrap_mode_override,
 1903            diagnostics_max_severity,
 1904            hard_wrap: None,
 1905            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1906            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1907            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1908            project,
 1909            blink_manager: blink_manager.clone(),
 1910            show_local_selections: true,
 1911            show_scrollbars: ScrollbarAxes {
 1912                horizontal: full_mode,
 1913                vertical: full_mode,
 1914            },
 1915            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1916            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1917            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1918            show_gutter: mode.is_full(),
 1919            show_line_numbers: None,
 1920            use_relative_line_numbers: None,
 1921            disable_expand_excerpt_buttons: false,
 1922            show_git_diff_gutter: None,
 1923            show_code_actions: None,
 1924            show_runnables: None,
 1925            show_breakpoints: None,
 1926            show_wrap_guides: None,
 1927            show_indent_guides,
 1928            placeholder_text: None,
 1929            highlight_order: 0,
 1930            highlighted_rows: HashMap::default(),
 1931            background_highlights: TreeMap::default(),
 1932            gutter_highlights: TreeMap::default(),
 1933            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1934            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1935            nav_history: None,
 1936            context_menu: RefCell::new(None),
 1937            context_menu_options: None,
 1938            mouse_context_menu: None,
 1939            completion_tasks: Vec::new(),
 1940            inline_blame_popover: None,
 1941            inline_blame_popover_show_task: None,
 1942            signature_help_state: SignatureHelpState::default(),
 1943            auto_signature_help: None,
 1944            find_all_references_task_sources: Vec::new(),
 1945            next_completion_id: 0,
 1946            next_inlay_id: 0,
 1947            code_action_providers,
 1948            available_code_actions: None,
 1949            code_actions_task: None,
 1950            quick_selection_highlight_task: None,
 1951            debounced_selection_highlight_task: None,
 1952            document_highlights_task: None,
 1953            linked_editing_range_task: None,
 1954            pending_rename: None,
 1955            searchable: true,
 1956            cursor_shape: EditorSettings::get_global(cx)
 1957                .cursor_shape
 1958                .unwrap_or_default(),
 1959            current_line_highlight: None,
 1960            autoindent_mode: Some(AutoindentMode::EachLine),
 1961            collapse_matches: false,
 1962            workspace: None,
 1963            input_enabled: true,
 1964            use_modal_editing: mode.is_full(),
 1965            read_only: mode.is_minimap(),
 1966            use_autoclose: true,
 1967            use_auto_surround: true,
 1968            auto_replace_emoji_shortcode: false,
 1969            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1970            leader_id: None,
 1971            remote_id: None,
 1972            hover_state: HoverState::default(),
 1973            pending_mouse_down: None,
 1974            hovered_link_state: None,
 1975            edit_prediction_provider: None,
 1976            active_inline_completion: None,
 1977            stale_inline_completion_in_menu: None,
 1978            edit_prediction_preview: EditPredictionPreview::Inactive {
 1979                released_too_fast: false,
 1980            },
 1981            inline_diagnostics_enabled: mode.is_full(),
 1982            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1983            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1984
 1985            gutter_hovered: false,
 1986            pixel_position_of_newest_cursor: None,
 1987            last_bounds: None,
 1988            last_position_map: None,
 1989            expect_bounds_change: None,
 1990            gutter_dimensions: GutterDimensions::default(),
 1991            style: None,
 1992            show_cursor_names: false,
 1993            hovered_cursors: HashMap::default(),
 1994            next_editor_action_id: EditorActionId::default(),
 1995            editor_actions: Rc::default(),
 1996            inline_completions_hidden_for_vim_mode: false,
 1997            show_inline_completions_override: None,
 1998            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1999            edit_prediction_settings: EditPredictionSettings::Disabled,
 2000            edit_prediction_indent_conflict: false,
 2001            edit_prediction_requires_modifier_in_indent_conflict: true,
 2002            custom_context_menu: None,
 2003            show_git_blame_gutter: false,
 2004            show_git_blame_inline: false,
 2005            show_selection_menu: None,
 2006            show_git_blame_inline_delay_task: None,
 2007            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2008            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2009            serialize_dirty_buffers: !mode.is_minimap()
 2010                && ProjectSettings::get_global(cx)
 2011                    .session
 2012                    .restore_unsaved_buffers,
 2013            blame: None,
 2014            blame_subscription: None,
 2015            tasks: BTreeMap::default(),
 2016
 2017            breakpoint_store,
 2018            gutter_breakpoint_indicator: (None, None),
 2019            _subscriptions: vec![
 2020                cx.observe(&buffer, Self::on_buffer_changed),
 2021                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2022                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2023                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2024                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2025                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2026                cx.observe_window_activation(window, |editor, window, cx| {
 2027                    let active = window.is_window_active();
 2028                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2029                        if active {
 2030                            blink_manager.enable(cx);
 2031                        } else {
 2032                            blink_manager.disable(cx);
 2033                        }
 2034                    });
 2035                    if active {
 2036                        editor.show_mouse_cursor();
 2037                    }
 2038                }),
 2039            ],
 2040            tasks_update_task: None,
 2041            pull_diagnostics_task: Task::ready(()),
 2042            linked_edit_ranges: Default::default(),
 2043            in_project_search: false,
 2044            previous_search_ranges: None,
 2045            breadcrumb_header: None,
 2046            focused_block: None,
 2047            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2048            addons: HashMap::default(),
 2049            registered_buffers: HashMap::default(),
 2050            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2051            selection_mark_mode: false,
 2052            toggle_fold_multiple_buffers: Task::ready(()),
 2053            serialize_selections: Task::ready(()),
 2054            serialize_folds: Task::ready(()),
 2055            text_style_refinement: None,
 2056            load_diff_task: load_uncommitted_diff,
 2057            temporary_diff_override: false,
 2058            mouse_cursor_hidden: false,
 2059            minimap: None,
 2060            hide_mouse_mode: EditorSettings::get_global(cx)
 2061                .hide_mouse
 2062                .unwrap_or_default(),
 2063            change_list: ChangeList::new(),
 2064            mode,
 2065            selection_drag_state: SelectionDragState::None,
 2066            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2067        };
 2068        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2069            editor
 2070                ._subscriptions
 2071                .push(cx.observe(breakpoints, |_, _, cx| {
 2072                    cx.notify();
 2073                }));
 2074        }
 2075        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2076        editor._subscriptions.extend(project_subscriptions);
 2077
 2078        editor._subscriptions.push(cx.subscribe_in(
 2079            &cx.entity(),
 2080            window,
 2081            |editor, _, e: &EditorEvent, window, cx| match e {
 2082                EditorEvent::ScrollPositionChanged { local, .. } => {
 2083                    if *local {
 2084                        let new_anchor = editor.scroll_manager.anchor();
 2085                        let snapshot = editor.snapshot(window, cx);
 2086                        editor.update_restoration_data(cx, move |data| {
 2087                            data.scroll_position = (
 2088                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2089                                new_anchor.offset,
 2090                            );
 2091                        });
 2092                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2093                        editor.inline_blame_popover.take();
 2094                    }
 2095                }
 2096                EditorEvent::Edited { .. } => {
 2097                    if !vim_enabled(cx) {
 2098                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2099                        let pop_state = editor
 2100                            .change_list
 2101                            .last()
 2102                            .map(|previous| {
 2103                                previous.len() == selections.len()
 2104                                    && previous.iter().enumerate().all(|(ix, p)| {
 2105                                        p.to_display_point(&map).row()
 2106                                            == selections[ix].head().row()
 2107                                    })
 2108                            })
 2109                            .unwrap_or(false);
 2110                        let new_positions = selections
 2111                            .into_iter()
 2112                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2113                            .collect();
 2114                        editor
 2115                            .change_list
 2116                            .push_to_change_list(pop_state, new_positions);
 2117                    }
 2118                }
 2119                _ => (),
 2120            },
 2121        ));
 2122
 2123        if let Some(dap_store) = editor
 2124            .project
 2125            .as_ref()
 2126            .map(|project| project.read(cx).dap_store())
 2127        {
 2128            let weak_editor = cx.weak_entity();
 2129
 2130            editor
 2131                ._subscriptions
 2132                .push(
 2133                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2134                        let session_entity = cx.entity();
 2135                        weak_editor
 2136                            .update(cx, |editor, cx| {
 2137                                editor._subscriptions.push(
 2138                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2139                                );
 2140                            })
 2141                            .ok();
 2142                    }),
 2143                );
 2144
 2145            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2146                editor
 2147                    ._subscriptions
 2148                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2149            }
 2150        }
 2151
 2152        // skip adding the initial selection to selection history
 2153        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2154        editor.end_selection(window, cx);
 2155        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2156
 2157        editor.scroll_manager.show_scrollbars(window, cx);
 2158        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2159
 2160        if full_mode {
 2161            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2162            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2163
 2164            if editor.git_blame_inline_enabled {
 2165                editor.start_git_blame_inline(false, window, cx);
 2166            }
 2167
 2168            editor.go_to_active_debug_line(window, cx);
 2169
 2170            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2171                if let Some(project) = editor.project.as_ref() {
 2172                    let handle = project.update(cx, |project, cx| {
 2173                        project.register_buffer_with_language_servers(&buffer, cx)
 2174                    });
 2175                    editor
 2176                        .registered_buffers
 2177                        .insert(buffer.read(cx).remote_id(), handle);
 2178                }
 2179            }
 2180
 2181            editor.minimap =
 2182                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2183            editor.pull_diagnostics(None, window, cx);
 2184        }
 2185
 2186        editor.report_editor_event("Editor Opened", None, cx);
 2187        editor
 2188    }
 2189
 2190    pub fn deploy_mouse_context_menu(
 2191        &mut self,
 2192        position: gpui::Point<Pixels>,
 2193        context_menu: Entity<ContextMenu>,
 2194        window: &mut Window,
 2195        cx: &mut Context<Self>,
 2196    ) {
 2197        self.mouse_context_menu = Some(MouseContextMenu::new(
 2198            self,
 2199            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2200            context_menu,
 2201            window,
 2202            cx,
 2203        ));
 2204    }
 2205
 2206    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2207        self.mouse_context_menu
 2208            .as_ref()
 2209            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2210    }
 2211
 2212    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2213        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2214    }
 2215
 2216    fn key_context_internal(
 2217        &self,
 2218        has_active_edit_prediction: bool,
 2219        window: &Window,
 2220        cx: &App,
 2221    ) -> KeyContext {
 2222        let mut key_context = KeyContext::new_with_defaults();
 2223        key_context.add("Editor");
 2224        let mode = match self.mode {
 2225            EditorMode::SingleLine { .. } => "single_line",
 2226            EditorMode::AutoHeight { .. } => "auto_height",
 2227            EditorMode::Minimap { .. } => "minimap",
 2228            EditorMode::Full { .. } => "full",
 2229        };
 2230
 2231        if EditorSettings::jupyter_enabled(cx) {
 2232            key_context.add("jupyter");
 2233        }
 2234
 2235        key_context.set("mode", mode);
 2236        if self.pending_rename.is_some() {
 2237            key_context.add("renaming");
 2238        }
 2239
 2240        match self.context_menu.borrow().as_ref() {
 2241            Some(CodeContextMenu::Completions(_)) => {
 2242                key_context.add("menu");
 2243                key_context.add("showing_completions");
 2244            }
 2245            Some(CodeContextMenu::CodeActions(_)) => {
 2246                key_context.add("menu");
 2247                key_context.add("showing_code_actions")
 2248            }
 2249            None => {}
 2250        }
 2251
 2252        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2253        if !self.focus_handle(cx).contains_focused(window, cx)
 2254            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2255        {
 2256            for addon in self.addons.values() {
 2257                addon.extend_key_context(&mut key_context, cx)
 2258            }
 2259        }
 2260
 2261        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2262            if let Some(extension) = singleton_buffer
 2263                .read(cx)
 2264                .file()
 2265                .and_then(|file| file.path().extension()?.to_str())
 2266            {
 2267                key_context.set("extension", extension.to_string());
 2268            }
 2269        } else {
 2270            key_context.add("multibuffer");
 2271        }
 2272
 2273        if has_active_edit_prediction {
 2274            if self.edit_prediction_in_conflict() {
 2275                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2276            } else {
 2277                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2278                key_context.add("copilot_suggestion");
 2279            }
 2280        }
 2281
 2282        if self.selection_mark_mode {
 2283            key_context.add("selection_mode");
 2284        }
 2285
 2286        key_context
 2287    }
 2288
 2289    fn show_mouse_cursor(&mut self) {
 2290        self.mouse_cursor_hidden = false;
 2291    }
 2292
 2293    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2294        self.mouse_cursor_hidden = match origin {
 2295            HideMouseCursorOrigin::TypingAction => {
 2296                matches!(
 2297                    self.hide_mouse_mode,
 2298                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2299                )
 2300            }
 2301            HideMouseCursorOrigin::MovementAction => {
 2302                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2303            }
 2304        };
 2305    }
 2306
 2307    pub fn edit_prediction_in_conflict(&self) -> bool {
 2308        if !self.show_edit_predictions_in_menu() {
 2309            return false;
 2310        }
 2311
 2312        let showing_completions = self
 2313            .context_menu
 2314            .borrow()
 2315            .as_ref()
 2316            .map_or(false, |context| {
 2317                matches!(context, CodeContextMenu::Completions(_))
 2318            });
 2319
 2320        showing_completions
 2321            || self.edit_prediction_requires_modifier()
 2322            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2323            // bindings to insert tab characters.
 2324            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2325    }
 2326
 2327    pub fn accept_edit_prediction_keybind(
 2328        &self,
 2329        accept_partial: bool,
 2330        window: &Window,
 2331        cx: &App,
 2332    ) -> AcceptEditPredictionBinding {
 2333        let key_context = self.key_context_internal(true, window, cx);
 2334        let in_conflict = self.edit_prediction_in_conflict();
 2335
 2336        let bindings = if accept_partial {
 2337            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2338        } else {
 2339            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2340        };
 2341
 2342        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2343        // just the first one.
 2344        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2345            !in_conflict
 2346                || binding
 2347                    .keystrokes()
 2348                    .first()
 2349                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2350        }))
 2351    }
 2352
 2353    pub fn new_file(
 2354        workspace: &mut Workspace,
 2355        _: &workspace::NewFile,
 2356        window: &mut Window,
 2357        cx: &mut Context<Workspace>,
 2358    ) {
 2359        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2360            "Failed to create buffer",
 2361            window,
 2362            cx,
 2363            |e, _, _| match e.error_code() {
 2364                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2365                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2366                e.error_tag("required").unwrap_or("the latest version")
 2367            )),
 2368                _ => None,
 2369            },
 2370        );
 2371    }
 2372
 2373    pub fn new_in_workspace(
 2374        workspace: &mut Workspace,
 2375        window: &mut Window,
 2376        cx: &mut Context<Workspace>,
 2377    ) -> Task<Result<Entity<Editor>>> {
 2378        let project = workspace.project().clone();
 2379        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2380
 2381        cx.spawn_in(window, async move |workspace, cx| {
 2382            let buffer = create.await?;
 2383            workspace.update_in(cx, |workspace, window, cx| {
 2384                let editor =
 2385                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2386                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2387                editor
 2388            })
 2389        })
 2390    }
 2391
 2392    fn new_file_vertical(
 2393        workspace: &mut Workspace,
 2394        _: &workspace::NewFileSplitVertical,
 2395        window: &mut Window,
 2396        cx: &mut Context<Workspace>,
 2397    ) {
 2398        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2399    }
 2400
 2401    fn new_file_horizontal(
 2402        workspace: &mut Workspace,
 2403        _: &workspace::NewFileSplitHorizontal,
 2404        window: &mut Window,
 2405        cx: &mut Context<Workspace>,
 2406    ) {
 2407        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2408    }
 2409
 2410    fn new_file_in_direction(
 2411        workspace: &mut Workspace,
 2412        direction: SplitDirection,
 2413        window: &mut Window,
 2414        cx: &mut Context<Workspace>,
 2415    ) {
 2416        let project = workspace.project().clone();
 2417        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2418
 2419        cx.spawn_in(window, async move |workspace, cx| {
 2420            let buffer = create.await?;
 2421            workspace.update_in(cx, move |workspace, window, cx| {
 2422                workspace.split_item(
 2423                    direction,
 2424                    Box::new(
 2425                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2426                    ),
 2427                    window,
 2428                    cx,
 2429                )
 2430            })?;
 2431            anyhow::Ok(())
 2432        })
 2433        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2434            match e.error_code() {
 2435                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2436                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2437                e.error_tag("required").unwrap_or("the latest version")
 2438            )),
 2439                _ => None,
 2440            }
 2441        });
 2442    }
 2443
 2444    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2445        self.leader_id
 2446    }
 2447
 2448    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2449        &self.buffer
 2450    }
 2451
 2452    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2453        self.workspace.as_ref()?.0.upgrade()
 2454    }
 2455
 2456    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2457        self.buffer().read(cx).title(cx)
 2458    }
 2459
 2460    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2461        let git_blame_gutter_max_author_length = self
 2462            .render_git_blame_gutter(cx)
 2463            .then(|| {
 2464                if let Some(blame) = self.blame.as_ref() {
 2465                    let max_author_length =
 2466                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2467                    Some(max_author_length)
 2468                } else {
 2469                    None
 2470                }
 2471            })
 2472            .flatten();
 2473
 2474        EditorSnapshot {
 2475            mode: self.mode.clone(),
 2476            show_gutter: self.show_gutter,
 2477            show_line_numbers: self.show_line_numbers,
 2478            show_git_diff_gutter: self.show_git_diff_gutter,
 2479            show_code_actions: self.show_code_actions,
 2480            show_runnables: self.show_runnables,
 2481            show_breakpoints: self.show_breakpoints,
 2482            git_blame_gutter_max_author_length,
 2483            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2484            scroll_anchor: self.scroll_manager.anchor(),
 2485            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2486            placeholder_text: self.placeholder_text.clone(),
 2487            is_focused: self.focus_handle.is_focused(window),
 2488            current_line_highlight: self
 2489                .current_line_highlight
 2490                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2491            gutter_hovered: self.gutter_hovered,
 2492        }
 2493    }
 2494
 2495    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2496        self.buffer.read(cx).language_at(point, cx)
 2497    }
 2498
 2499    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2500        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2501    }
 2502
 2503    pub fn active_excerpt(
 2504        &self,
 2505        cx: &App,
 2506    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2507        self.buffer
 2508            .read(cx)
 2509            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2510    }
 2511
 2512    pub fn mode(&self) -> &EditorMode {
 2513        &self.mode
 2514    }
 2515
 2516    pub fn set_mode(&mut self, mode: EditorMode) {
 2517        self.mode = mode;
 2518    }
 2519
 2520    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2521        self.collaboration_hub.as_deref()
 2522    }
 2523
 2524    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2525        self.collaboration_hub = Some(hub);
 2526    }
 2527
 2528    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2529        self.in_project_search = in_project_search;
 2530    }
 2531
 2532    pub fn set_custom_context_menu(
 2533        &mut self,
 2534        f: impl 'static
 2535        + Fn(
 2536            &mut Self,
 2537            DisplayPoint,
 2538            &mut Window,
 2539            &mut Context<Self>,
 2540        ) -> Option<Entity<ui::ContextMenu>>,
 2541    ) {
 2542        self.custom_context_menu = Some(Box::new(f))
 2543    }
 2544
 2545    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2546        self.completion_provider = provider;
 2547    }
 2548
 2549    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2550        self.semantics_provider.clone()
 2551    }
 2552
 2553    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2554        self.semantics_provider = provider;
 2555    }
 2556
 2557    pub fn set_edit_prediction_provider<T>(
 2558        &mut self,
 2559        provider: Option<Entity<T>>,
 2560        window: &mut Window,
 2561        cx: &mut Context<Self>,
 2562    ) where
 2563        T: EditPredictionProvider,
 2564    {
 2565        self.edit_prediction_provider =
 2566            provider.map(|provider| RegisteredInlineCompletionProvider {
 2567                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2568                    if this.focus_handle.is_focused(window) {
 2569                        this.update_visible_inline_completion(window, cx);
 2570                    }
 2571                }),
 2572                provider: Arc::new(provider),
 2573            });
 2574        self.update_edit_prediction_settings(cx);
 2575        self.refresh_inline_completion(false, false, window, cx);
 2576    }
 2577
 2578    pub fn placeholder_text(&self) -> Option<&str> {
 2579        self.placeholder_text.as_deref()
 2580    }
 2581
 2582    pub fn set_placeholder_text(
 2583        &mut self,
 2584        placeholder_text: impl Into<Arc<str>>,
 2585        cx: &mut Context<Self>,
 2586    ) {
 2587        let placeholder_text = Some(placeholder_text.into());
 2588        if self.placeholder_text != placeholder_text {
 2589            self.placeholder_text = placeholder_text;
 2590            cx.notify();
 2591        }
 2592    }
 2593
 2594    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2595        self.cursor_shape = cursor_shape;
 2596
 2597        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2598        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2599
 2600        cx.notify();
 2601    }
 2602
 2603    pub fn set_current_line_highlight(
 2604        &mut self,
 2605        current_line_highlight: Option<CurrentLineHighlight>,
 2606    ) {
 2607        self.current_line_highlight = current_line_highlight;
 2608    }
 2609
 2610    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2611        self.collapse_matches = collapse_matches;
 2612    }
 2613
 2614    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2615        let buffers = self.buffer.read(cx).all_buffers();
 2616        let Some(project) = self.project.as_ref() else {
 2617            return;
 2618        };
 2619        project.update(cx, |project, cx| {
 2620            for buffer in buffers {
 2621                self.registered_buffers
 2622                    .entry(buffer.read(cx).remote_id())
 2623                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2624            }
 2625        })
 2626    }
 2627
 2628    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2629        if self.collapse_matches {
 2630            return range.start..range.start;
 2631        }
 2632        range.clone()
 2633    }
 2634
 2635    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2636        if self.display_map.read(cx).clip_at_line_ends != clip {
 2637            self.display_map
 2638                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2639        }
 2640    }
 2641
 2642    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2643        self.input_enabled = input_enabled;
 2644    }
 2645
 2646    pub fn set_inline_completions_hidden_for_vim_mode(
 2647        &mut self,
 2648        hidden: bool,
 2649        window: &mut Window,
 2650        cx: &mut Context<Self>,
 2651    ) {
 2652        if hidden != self.inline_completions_hidden_for_vim_mode {
 2653            self.inline_completions_hidden_for_vim_mode = hidden;
 2654            if hidden {
 2655                self.update_visible_inline_completion(window, cx);
 2656            } else {
 2657                self.refresh_inline_completion(true, false, window, cx);
 2658            }
 2659        }
 2660    }
 2661
 2662    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2663        self.menu_inline_completions_policy = value;
 2664    }
 2665
 2666    pub fn set_autoindent(&mut self, autoindent: bool) {
 2667        if autoindent {
 2668            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2669        } else {
 2670            self.autoindent_mode = None;
 2671        }
 2672    }
 2673
 2674    pub fn read_only(&self, cx: &App) -> bool {
 2675        self.read_only || self.buffer.read(cx).read_only()
 2676    }
 2677
 2678    pub fn set_read_only(&mut self, read_only: bool) {
 2679        self.read_only = read_only;
 2680    }
 2681
 2682    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2683        self.use_autoclose = autoclose;
 2684    }
 2685
 2686    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2687        self.use_auto_surround = auto_surround;
 2688    }
 2689
 2690    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2691        self.auto_replace_emoji_shortcode = auto_replace;
 2692    }
 2693
 2694    pub fn toggle_edit_predictions(
 2695        &mut self,
 2696        _: &ToggleEditPrediction,
 2697        window: &mut Window,
 2698        cx: &mut Context<Self>,
 2699    ) {
 2700        if self.show_inline_completions_override.is_some() {
 2701            self.set_show_edit_predictions(None, window, cx);
 2702        } else {
 2703            let show_edit_predictions = !self.edit_predictions_enabled();
 2704            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2705        }
 2706    }
 2707
 2708    pub fn set_show_edit_predictions(
 2709        &mut self,
 2710        show_edit_predictions: Option<bool>,
 2711        window: &mut Window,
 2712        cx: &mut Context<Self>,
 2713    ) {
 2714        self.show_inline_completions_override = show_edit_predictions;
 2715        self.update_edit_prediction_settings(cx);
 2716
 2717        if let Some(false) = show_edit_predictions {
 2718            self.discard_inline_completion(false, cx);
 2719        } else {
 2720            self.refresh_inline_completion(false, true, window, cx);
 2721        }
 2722    }
 2723
 2724    fn inline_completions_disabled_in_scope(
 2725        &self,
 2726        buffer: &Entity<Buffer>,
 2727        buffer_position: language::Anchor,
 2728        cx: &App,
 2729    ) -> bool {
 2730        let snapshot = buffer.read(cx).snapshot();
 2731        let settings = snapshot.settings_at(buffer_position, cx);
 2732
 2733        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2734            return false;
 2735        };
 2736
 2737        scope.override_name().map_or(false, |scope_name| {
 2738            settings
 2739                .edit_predictions_disabled_in
 2740                .iter()
 2741                .any(|s| s == scope_name)
 2742        })
 2743    }
 2744
 2745    pub fn set_use_modal_editing(&mut self, to: bool) {
 2746        self.use_modal_editing = to;
 2747    }
 2748
 2749    pub fn use_modal_editing(&self) -> bool {
 2750        self.use_modal_editing
 2751    }
 2752
 2753    fn selections_did_change(
 2754        &mut self,
 2755        local: bool,
 2756        old_cursor_position: &Anchor,
 2757        effects: SelectionEffects,
 2758        window: &mut Window,
 2759        cx: &mut Context<Self>,
 2760    ) {
 2761        window.invalidate_character_coordinates();
 2762
 2763        // Copy selections to primary selection buffer
 2764        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2765        if local {
 2766            let selections = self.selections.all::<usize>(cx);
 2767            let buffer_handle = self.buffer.read(cx).read(cx);
 2768
 2769            let mut text = String::new();
 2770            for (index, selection) in selections.iter().enumerate() {
 2771                let text_for_selection = buffer_handle
 2772                    .text_for_range(selection.start..selection.end)
 2773                    .collect::<String>();
 2774
 2775                text.push_str(&text_for_selection);
 2776                if index != selections.len() - 1 {
 2777                    text.push('\n');
 2778                }
 2779            }
 2780
 2781            if !text.is_empty() {
 2782                cx.write_to_primary(ClipboardItem::new_string(text));
 2783            }
 2784        }
 2785
 2786        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2787            self.buffer.update(cx, |buffer, cx| {
 2788                buffer.set_active_selections(
 2789                    &self.selections.disjoint_anchors(),
 2790                    self.selections.line_mode,
 2791                    self.cursor_shape,
 2792                    cx,
 2793                )
 2794            });
 2795        }
 2796        let display_map = self
 2797            .display_map
 2798            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2799        let buffer = &display_map.buffer_snapshot;
 2800        if self.selections.count() == 1 {
 2801            self.add_selections_state = None;
 2802        }
 2803        self.select_next_state = None;
 2804        self.select_prev_state = None;
 2805        self.select_syntax_node_history.try_clear();
 2806        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2807        self.snippet_stack
 2808            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2809        self.take_rename(false, window, cx);
 2810
 2811        let newest_selection = self.selections.newest_anchor();
 2812        let new_cursor_position = newest_selection.head();
 2813        let selection_start = newest_selection.start;
 2814
 2815        if effects.nav_history {
 2816            self.push_to_nav_history(
 2817                *old_cursor_position,
 2818                Some(new_cursor_position.to_point(buffer)),
 2819                false,
 2820                cx,
 2821            );
 2822        }
 2823
 2824        if local {
 2825            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2826                if !self.registered_buffers.contains_key(&buffer_id) {
 2827                    if let Some(project) = self.project.as_ref() {
 2828                        project.update(cx, |project, cx| {
 2829                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2830                                return;
 2831                            };
 2832                            self.registered_buffers.insert(
 2833                                buffer_id,
 2834                                project.register_buffer_with_language_servers(&buffer, cx),
 2835                            );
 2836                        })
 2837                    }
 2838                }
 2839            }
 2840
 2841            let mut context_menu = self.context_menu.borrow_mut();
 2842            let completion_menu = match context_menu.as_ref() {
 2843                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2844                Some(CodeContextMenu::CodeActions(_)) => {
 2845                    *context_menu = None;
 2846                    None
 2847                }
 2848                None => None,
 2849            };
 2850            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2851            drop(context_menu);
 2852
 2853            if effects.completions {
 2854                if let Some(completion_position) = completion_position {
 2855                    let start_offset = selection_start.to_offset(buffer);
 2856                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2857                    let continue_showing = if position_matches {
 2858                        if self.snippet_stack.is_empty() {
 2859                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2860                        } else {
 2861                            // Snippet choices can be shown even when the cursor is in whitespace.
 2862                            // Dismissing the menu when actions like backspace
 2863                            true
 2864                        }
 2865                    } else {
 2866                        false
 2867                    };
 2868
 2869                    if continue_showing {
 2870                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2871                    } else {
 2872                        self.hide_context_menu(window, cx);
 2873                    }
 2874                }
 2875            }
 2876
 2877            hide_hover(self, cx);
 2878
 2879            if old_cursor_position.to_display_point(&display_map).row()
 2880                != new_cursor_position.to_display_point(&display_map).row()
 2881            {
 2882                self.available_code_actions.take();
 2883            }
 2884            self.refresh_code_actions(window, cx);
 2885            self.refresh_document_highlights(cx);
 2886            self.refresh_selected_text_highlights(false, window, cx);
 2887            refresh_matching_bracket_highlights(self, window, cx);
 2888            self.update_visible_inline_completion(window, cx);
 2889            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2890            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2891            self.inline_blame_popover.take();
 2892            if self.git_blame_inline_enabled {
 2893                self.start_inline_blame_timer(window, cx);
 2894            }
 2895        }
 2896
 2897        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2898        cx.emit(EditorEvent::SelectionsChanged { local });
 2899
 2900        let selections = &self.selections.disjoint;
 2901        if selections.len() == 1 {
 2902            cx.emit(SearchEvent::ActiveMatchChanged)
 2903        }
 2904        if local {
 2905            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2906                let inmemory_selections = selections
 2907                    .iter()
 2908                    .map(|s| {
 2909                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2910                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2911                    })
 2912                    .collect();
 2913                self.update_restoration_data(cx, |data| {
 2914                    data.selections = inmemory_selections;
 2915                });
 2916
 2917                if WorkspaceSettings::get(None, cx).restore_on_startup
 2918                    != RestoreOnStartupBehavior::None
 2919                {
 2920                    if let Some(workspace_id) =
 2921                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2922                    {
 2923                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2924                        let selections = selections.clone();
 2925                        let background_executor = cx.background_executor().clone();
 2926                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2927                        self.serialize_selections = cx.background_spawn(async move {
 2928                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2929                    let db_selections = selections
 2930                        .iter()
 2931                        .map(|selection| {
 2932                            (
 2933                                selection.start.to_offset(&snapshot),
 2934                                selection.end.to_offset(&snapshot),
 2935                            )
 2936                        })
 2937                        .collect();
 2938
 2939                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2940                        .await
 2941                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2942                        .log_err();
 2943                });
 2944                    }
 2945                }
 2946            }
 2947        }
 2948
 2949        cx.notify();
 2950    }
 2951
 2952    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2953        use text::ToOffset as _;
 2954        use text::ToPoint as _;
 2955
 2956        if self.mode.is_minimap()
 2957            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2958        {
 2959            return;
 2960        }
 2961
 2962        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2963            return;
 2964        };
 2965
 2966        let snapshot = singleton.read(cx).snapshot();
 2967        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2968            let display_snapshot = display_map.snapshot(cx);
 2969
 2970            display_snapshot
 2971                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2972                .map(|fold| {
 2973                    fold.range.start.text_anchor.to_point(&snapshot)
 2974                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2975                })
 2976                .collect()
 2977        });
 2978        self.update_restoration_data(cx, |data| {
 2979            data.folds = inmemory_folds;
 2980        });
 2981
 2982        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2983            return;
 2984        };
 2985        let background_executor = cx.background_executor().clone();
 2986        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2987        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2988            display_map
 2989                .snapshot(cx)
 2990                .folds_in_range(0..snapshot.len())
 2991                .map(|fold| {
 2992                    (
 2993                        fold.range.start.text_anchor.to_offset(&snapshot),
 2994                        fold.range.end.text_anchor.to_offset(&snapshot),
 2995                    )
 2996                })
 2997                .collect()
 2998        });
 2999        self.serialize_folds = cx.background_spawn(async move {
 3000            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3001            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3002                .await
 3003                .with_context(|| {
 3004                    format!(
 3005                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3006                    )
 3007                })
 3008                .log_err();
 3009        });
 3010    }
 3011
 3012    pub fn sync_selections(
 3013        &mut self,
 3014        other: Entity<Editor>,
 3015        cx: &mut Context<Self>,
 3016    ) -> gpui::Subscription {
 3017        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3018        self.selections.change_with(cx, |selections| {
 3019            selections.select_anchors(other_selections);
 3020        });
 3021
 3022        let other_subscription =
 3023            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3024                EditorEvent::SelectionsChanged { local: true } => {
 3025                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3026                    if other_selections.is_empty() {
 3027                        return;
 3028                    }
 3029                    this.selections.change_with(cx, |selections| {
 3030                        selections.select_anchors(other_selections);
 3031                    });
 3032                }
 3033                _ => {}
 3034            });
 3035
 3036        let this_subscription =
 3037            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3038                EditorEvent::SelectionsChanged { local: true } => {
 3039                    let these_selections = this.selections.disjoint.to_vec();
 3040                    if these_selections.is_empty() {
 3041                        return;
 3042                    }
 3043                    other.update(cx, |other_editor, cx| {
 3044                        other_editor.selections.change_with(cx, |selections| {
 3045                            selections.select_anchors(these_selections);
 3046                        })
 3047                    });
 3048                }
 3049                _ => {}
 3050            });
 3051
 3052        Subscription::join(other_subscription, this_subscription)
 3053    }
 3054
 3055    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3056    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3057    /// effects of selection change occur at the end of the transaction.
 3058    pub fn change_selections<R>(
 3059        &mut self,
 3060        effects: impl Into<SelectionEffects>,
 3061        window: &mut Window,
 3062        cx: &mut Context<Self>,
 3063        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3064    ) -> R {
 3065        let effects = effects.into();
 3066        if let Some(state) = &mut self.deferred_selection_effects_state {
 3067            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3068            state.effects.completions = effects.completions;
 3069            state.effects.nav_history |= effects.nav_history;
 3070            let (changed, result) = self.selections.change_with(cx, change);
 3071            state.changed |= changed;
 3072            return result;
 3073        }
 3074        let mut state = DeferredSelectionEffectsState {
 3075            changed: false,
 3076            effects,
 3077            old_cursor_position: self.selections.newest_anchor().head(),
 3078            history_entry: SelectionHistoryEntry {
 3079                selections: self.selections.disjoint_anchors(),
 3080                select_next_state: self.select_next_state.clone(),
 3081                select_prev_state: self.select_prev_state.clone(),
 3082                add_selections_state: self.add_selections_state.clone(),
 3083            },
 3084        };
 3085        let (changed, result) = self.selections.change_with(cx, change);
 3086        state.changed = state.changed || changed;
 3087        if self.defer_selection_effects {
 3088            self.deferred_selection_effects_state = Some(state);
 3089        } else {
 3090            self.apply_selection_effects(state, window, cx);
 3091        }
 3092        result
 3093    }
 3094
 3095    /// Defers the effects of selection change, so that the effects of multiple calls to
 3096    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3097    /// to selection history and the state of popovers based on selection position aren't
 3098    /// erroneously updated.
 3099    pub fn with_selection_effects_deferred<R>(
 3100        &mut self,
 3101        window: &mut Window,
 3102        cx: &mut Context<Self>,
 3103        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3104    ) -> R {
 3105        let already_deferred = self.defer_selection_effects;
 3106        self.defer_selection_effects = true;
 3107        let result = update(self, window, cx);
 3108        if !already_deferred {
 3109            self.defer_selection_effects = false;
 3110            if let Some(state) = self.deferred_selection_effects_state.take() {
 3111                self.apply_selection_effects(state, window, cx);
 3112            }
 3113        }
 3114        result
 3115    }
 3116
 3117    fn apply_selection_effects(
 3118        &mut self,
 3119        state: DeferredSelectionEffectsState,
 3120        window: &mut Window,
 3121        cx: &mut Context<Self>,
 3122    ) {
 3123        if state.changed {
 3124            self.selection_history.push(state.history_entry);
 3125
 3126            if let Some(autoscroll) = state.effects.scroll {
 3127                self.request_autoscroll(autoscroll, cx);
 3128            }
 3129
 3130            let old_cursor_position = &state.old_cursor_position;
 3131
 3132            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3133
 3134            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3135                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3136            }
 3137        }
 3138    }
 3139
 3140    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3141    where
 3142        I: IntoIterator<Item = (Range<S>, T)>,
 3143        S: ToOffset,
 3144        T: Into<Arc<str>>,
 3145    {
 3146        if self.read_only(cx) {
 3147            return;
 3148        }
 3149
 3150        self.buffer
 3151            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3152    }
 3153
 3154    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3155    where
 3156        I: IntoIterator<Item = (Range<S>, T)>,
 3157        S: ToOffset,
 3158        T: Into<Arc<str>>,
 3159    {
 3160        if self.read_only(cx) {
 3161            return;
 3162        }
 3163
 3164        self.buffer.update(cx, |buffer, cx| {
 3165            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3166        });
 3167    }
 3168
 3169    pub fn edit_with_block_indent<I, S, T>(
 3170        &mut self,
 3171        edits: I,
 3172        original_indent_columns: Vec<Option<u32>>,
 3173        cx: &mut Context<Self>,
 3174    ) where
 3175        I: IntoIterator<Item = (Range<S>, T)>,
 3176        S: ToOffset,
 3177        T: Into<Arc<str>>,
 3178    {
 3179        if self.read_only(cx) {
 3180            return;
 3181        }
 3182
 3183        self.buffer.update(cx, |buffer, cx| {
 3184            buffer.edit(
 3185                edits,
 3186                Some(AutoindentMode::Block {
 3187                    original_indent_columns,
 3188                }),
 3189                cx,
 3190            )
 3191        });
 3192    }
 3193
 3194    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3195        self.hide_context_menu(window, cx);
 3196
 3197        match phase {
 3198            SelectPhase::Begin {
 3199                position,
 3200                add,
 3201                click_count,
 3202            } => self.begin_selection(position, add, click_count, window, cx),
 3203            SelectPhase::BeginColumnar {
 3204                position,
 3205                goal_column,
 3206                reset,
 3207            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3208            SelectPhase::Extend {
 3209                position,
 3210                click_count,
 3211            } => self.extend_selection(position, click_count, window, cx),
 3212            SelectPhase::Update {
 3213                position,
 3214                goal_column,
 3215                scroll_delta,
 3216            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3217            SelectPhase::End => self.end_selection(window, cx),
 3218        }
 3219    }
 3220
 3221    fn extend_selection(
 3222        &mut self,
 3223        position: DisplayPoint,
 3224        click_count: usize,
 3225        window: &mut Window,
 3226        cx: &mut Context<Self>,
 3227    ) {
 3228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3229        let tail = self.selections.newest::<usize>(cx).tail();
 3230        self.begin_selection(position, false, click_count, window, cx);
 3231
 3232        let position = position.to_offset(&display_map, Bias::Left);
 3233        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3234
 3235        let mut pending_selection = self
 3236            .selections
 3237            .pending_anchor()
 3238            .expect("extend_selection not called with pending selection");
 3239        if position >= tail {
 3240            pending_selection.start = tail_anchor;
 3241        } else {
 3242            pending_selection.end = tail_anchor;
 3243            pending_selection.reversed = true;
 3244        }
 3245
 3246        let mut pending_mode = self.selections.pending_mode().unwrap();
 3247        match &mut pending_mode {
 3248            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3249            _ => {}
 3250        }
 3251
 3252        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3253            SelectionEffects::scroll(Autoscroll::fit())
 3254        } else {
 3255            SelectionEffects::no_scroll()
 3256        };
 3257
 3258        self.change_selections(effects, window, cx, |s| {
 3259            s.set_pending(pending_selection, pending_mode)
 3260        });
 3261    }
 3262
 3263    fn begin_selection(
 3264        &mut self,
 3265        position: DisplayPoint,
 3266        add: bool,
 3267        click_count: usize,
 3268        window: &mut Window,
 3269        cx: &mut Context<Self>,
 3270    ) {
 3271        if !self.focus_handle.is_focused(window) {
 3272            self.last_focused_descendant = None;
 3273            window.focus(&self.focus_handle);
 3274        }
 3275
 3276        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3277        let buffer = &display_map.buffer_snapshot;
 3278        let position = display_map.clip_point(position, Bias::Left);
 3279
 3280        let start;
 3281        let end;
 3282        let mode;
 3283        let mut auto_scroll;
 3284        match click_count {
 3285            1 => {
 3286                start = buffer.anchor_before(position.to_point(&display_map));
 3287                end = start;
 3288                mode = SelectMode::Character;
 3289                auto_scroll = true;
 3290            }
 3291            2 => {
 3292                let range = movement::surrounding_word(&display_map, position);
 3293                start = buffer.anchor_before(range.start.to_point(&display_map));
 3294                end = buffer.anchor_before(range.end.to_point(&display_map));
 3295                mode = SelectMode::Word(start..end);
 3296                auto_scroll = true;
 3297            }
 3298            3 => {
 3299                let position = display_map
 3300                    .clip_point(position, Bias::Left)
 3301                    .to_point(&display_map);
 3302                let line_start = display_map.prev_line_boundary(position).0;
 3303                let next_line_start = buffer.clip_point(
 3304                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3305                    Bias::Left,
 3306                );
 3307                start = buffer.anchor_before(line_start);
 3308                end = buffer.anchor_before(next_line_start);
 3309                mode = SelectMode::Line(start..end);
 3310                auto_scroll = true;
 3311            }
 3312            _ => {
 3313                start = buffer.anchor_before(0);
 3314                end = buffer.anchor_before(buffer.len());
 3315                mode = SelectMode::All;
 3316                auto_scroll = false;
 3317            }
 3318        }
 3319        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3320
 3321        let point_to_delete: Option<usize> = {
 3322            let selected_points: Vec<Selection<Point>> =
 3323                self.selections.disjoint_in_range(start..end, cx);
 3324
 3325            if !add || click_count > 1 {
 3326                None
 3327            } else if !selected_points.is_empty() {
 3328                Some(selected_points[0].id)
 3329            } else {
 3330                let clicked_point_already_selected =
 3331                    self.selections.disjoint.iter().find(|selection| {
 3332                        selection.start.to_point(buffer) == start.to_point(buffer)
 3333                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3334                    });
 3335
 3336                clicked_point_already_selected.map(|selection| selection.id)
 3337            }
 3338        };
 3339
 3340        let selections_count = self.selections.count();
 3341
 3342        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3343            if let Some(point_to_delete) = point_to_delete {
 3344                s.delete(point_to_delete);
 3345
 3346                if selections_count == 1 {
 3347                    s.set_pending_anchor_range(start..end, mode);
 3348                }
 3349            } else {
 3350                if !add {
 3351                    s.clear_disjoint();
 3352                }
 3353
 3354                s.set_pending_anchor_range(start..end, mode);
 3355            }
 3356        });
 3357    }
 3358
 3359    fn begin_columnar_selection(
 3360        &mut self,
 3361        position: DisplayPoint,
 3362        goal_column: u32,
 3363        reset: bool,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366    ) {
 3367        if !self.focus_handle.is_focused(window) {
 3368            self.last_focused_descendant = None;
 3369            window.focus(&self.focus_handle);
 3370        }
 3371
 3372        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3373
 3374        if reset {
 3375            let pointer_position = display_map
 3376                .buffer_snapshot
 3377                .anchor_before(position.to_point(&display_map));
 3378
 3379            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3380                s.clear_disjoint();
 3381                s.set_pending_anchor_range(
 3382                    pointer_position..pointer_position,
 3383                    SelectMode::Character,
 3384                );
 3385            });
 3386            if position.column() != goal_column {
 3387                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3388            } else {
 3389                self.columnar_display_point = None;
 3390            }
 3391        }
 3392
 3393        let tail = self.selections.newest::<Point>(cx).tail();
 3394        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3395
 3396        if !reset {
 3397            self.columnar_display_point = None;
 3398            self.select_columns(
 3399                tail.to_display_point(&display_map),
 3400                position,
 3401                goal_column,
 3402                &display_map,
 3403                window,
 3404                cx,
 3405            );
 3406        }
 3407    }
 3408
 3409    fn update_selection(
 3410        &mut self,
 3411        position: DisplayPoint,
 3412        goal_column: u32,
 3413        scroll_delta: gpui::Point<f32>,
 3414        window: &mut Window,
 3415        cx: &mut Context<Self>,
 3416    ) {
 3417        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3418
 3419        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3420            let tail = self
 3421                .columnar_display_point
 3422                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3423            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3424        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3425            let buffer = self.buffer.read(cx).snapshot(cx);
 3426            let head;
 3427            let tail;
 3428            let mode = self.selections.pending_mode().unwrap();
 3429            match &mode {
 3430                SelectMode::Character => {
 3431                    head = position.to_point(&display_map);
 3432                    tail = pending.tail().to_point(&buffer);
 3433                }
 3434                SelectMode::Word(original_range) => {
 3435                    let original_display_range = original_range.start.to_display_point(&display_map)
 3436                        ..original_range.end.to_display_point(&display_map);
 3437                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3438                        ..original_display_range.end.to_point(&display_map);
 3439                    if movement::is_inside_word(&display_map, position)
 3440                        || original_display_range.contains(&position)
 3441                    {
 3442                        let word_range = movement::surrounding_word(&display_map, position);
 3443                        if word_range.start < original_display_range.start {
 3444                            head = word_range.start.to_point(&display_map);
 3445                        } else {
 3446                            head = word_range.end.to_point(&display_map);
 3447                        }
 3448                    } else {
 3449                        head = position.to_point(&display_map);
 3450                    }
 3451
 3452                    if head <= original_buffer_range.start {
 3453                        tail = original_buffer_range.end;
 3454                    } else {
 3455                        tail = original_buffer_range.start;
 3456                    }
 3457                }
 3458                SelectMode::Line(original_range) => {
 3459                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3460
 3461                    let position = display_map
 3462                        .clip_point(position, Bias::Left)
 3463                        .to_point(&display_map);
 3464                    let line_start = display_map.prev_line_boundary(position).0;
 3465                    let next_line_start = buffer.clip_point(
 3466                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3467                        Bias::Left,
 3468                    );
 3469
 3470                    if line_start < original_range.start {
 3471                        head = line_start
 3472                    } else {
 3473                        head = next_line_start
 3474                    }
 3475
 3476                    if head <= original_range.start {
 3477                        tail = original_range.end;
 3478                    } else {
 3479                        tail = original_range.start;
 3480                    }
 3481                }
 3482                SelectMode::All => {
 3483                    return;
 3484                }
 3485            };
 3486
 3487            if head < tail {
 3488                pending.start = buffer.anchor_before(head);
 3489                pending.end = buffer.anchor_before(tail);
 3490                pending.reversed = true;
 3491            } else {
 3492                pending.start = buffer.anchor_before(tail);
 3493                pending.end = buffer.anchor_before(head);
 3494                pending.reversed = false;
 3495            }
 3496
 3497            self.change_selections(None, window, cx, |s| {
 3498                s.set_pending(pending, mode);
 3499            });
 3500        } else {
 3501            log::error!("update_selection dispatched with no pending selection");
 3502            return;
 3503        }
 3504
 3505        self.apply_scroll_delta(scroll_delta, window, cx);
 3506        cx.notify();
 3507    }
 3508
 3509    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3510        self.columnar_selection_tail.take();
 3511        if self.selections.pending_anchor().is_some() {
 3512            let selections = self.selections.all::<usize>(cx);
 3513            self.change_selections(None, window, cx, |s| {
 3514                s.select(selections);
 3515                s.clear_pending();
 3516            });
 3517        }
 3518    }
 3519
 3520    fn select_columns(
 3521        &mut self,
 3522        tail: DisplayPoint,
 3523        head: DisplayPoint,
 3524        goal_column: u32,
 3525        display_map: &DisplaySnapshot,
 3526        window: &mut Window,
 3527        cx: &mut Context<Self>,
 3528    ) {
 3529        let start_row = cmp::min(tail.row(), head.row());
 3530        let end_row = cmp::max(tail.row(), head.row());
 3531        let start_column = cmp::min(tail.column(), goal_column);
 3532        let end_column = cmp::max(tail.column(), goal_column);
 3533        let reversed = start_column < tail.column();
 3534
 3535        let selection_ranges = (start_row.0..=end_row.0)
 3536            .map(DisplayRow)
 3537            .filter_map(|row| {
 3538                if !display_map.is_block_line(row) {
 3539                    let start = display_map
 3540                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3541                        .to_point(display_map);
 3542                    let end = display_map
 3543                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3544                        .to_point(display_map);
 3545                    if reversed {
 3546                        Some(end..start)
 3547                    } else {
 3548                        Some(start..end)
 3549                    }
 3550                } else {
 3551                    None
 3552                }
 3553            })
 3554            .collect::<Vec<_>>();
 3555
 3556        let mut non_empty_ranges = selection_ranges
 3557            .iter()
 3558            .filter(|selection_range| selection_range.start != selection_range.end)
 3559            .peekable();
 3560
 3561        let ranges = if non_empty_ranges.peek().is_some() {
 3562            non_empty_ranges.cloned().collect()
 3563        } else {
 3564            selection_ranges
 3565        };
 3566
 3567        self.change_selections(None, window, cx, |s| {
 3568            s.select_ranges(ranges);
 3569        });
 3570        cx.notify();
 3571    }
 3572
 3573    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3574        self.selections
 3575            .all_adjusted(cx)
 3576            .iter()
 3577            .any(|selection| !selection.is_empty())
 3578    }
 3579
 3580    pub fn has_pending_nonempty_selection(&self) -> bool {
 3581        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3582            Some(Selection { start, end, .. }) => start != end,
 3583            None => false,
 3584        };
 3585
 3586        pending_nonempty_selection
 3587            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3588    }
 3589
 3590    pub fn has_pending_selection(&self) -> bool {
 3591        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3592    }
 3593
 3594    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3595        self.selection_mark_mode = false;
 3596        self.selection_drag_state = SelectionDragState::None;
 3597
 3598        if self.clear_expanded_diff_hunks(cx) {
 3599            cx.notify();
 3600            return;
 3601        }
 3602        if self.dismiss_menus_and_popups(true, window, cx) {
 3603            return;
 3604        }
 3605
 3606        if self.mode.is_full()
 3607            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3608        {
 3609            return;
 3610        }
 3611
 3612        cx.propagate();
 3613    }
 3614
 3615    pub fn dismiss_menus_and_popups(
 3616        &mut self,
 3617        is_user_requested: bool,
 3618        window: &mut Window,
 3619        cx: &mut Context<Self>,
 3620    ) -> bool {
 3621        if self.take_rename(false, window, cx).is_some() {
 3622            return true;
 3623        }
 3624
 3625        if hide_hover(self, cx) {
 3626            return true;
 3627        }
 3628
 3629        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3630            return true;
 3631        }
 3632
 3633        if self.hide_context_menu(window, cx).is_some() {
 3634            return true;
 3635        }
 3636
 3637        if self.mouse_context_menu.take().is_some() {
 3638            return true;
 3639        }
 3640
 3641        if is_user_requested && self.discard_inline_completion(true, cx) {
 3642            return true;
 3643        }
 3644
 3645        if self.snippet_stack.pop().is_some() {
 3646            return true;
 3647        }
 3648
 3649        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3650            self.dismiss_diagnostics(cx);
 3651            return true;
 3652        }
 3653
 3654        false
 3655    }
 3656
 3657    fn linked_editing_ranges_for(
 3658        &self,
 3659        selection: Range<text::Anchor>,
 3660        cx: &App,
 3661    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3662        if self.linked_edit_ranges.is_empty() {
 3663            return None;
 3664        }
 3665        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3666            selection.end.buffer_id.and_then(|end_buffer_id| {
 3667                if selection.start.buffer_id != Some(end_buffer_id) {
 3668                    return None;
 3669                }
 3670                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3671                let snapshot = buffer.read(cx).snapshot();
 3672                self.linked_edit_ranges
 3673                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3674                    .map(|ranges| (ranges, snapshot, buffer))
 3675            })?;
 3676        use text::ToOffset as TO;
 3677        // find offset from the start of current range to current cursor position
 3678        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3679
 3680        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3681        let start_difference = start_offset - start_byte_offset;
 3682        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3683        let end_difference = end_offset - start_byte_offset;
 3684        // Current range has associated linked ranges.
 3685        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3686        for range in linked_ranges.iter() {
 3687            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3688            let end_offset = start_offset + end_difference;
 3689            let start_offset = start_offset + start_difference;
 3690            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3691                continue;
 3692            }
 3693            if self.selections.disjoint_anchor_ranges().any(|s| {
 3694                if s.start.buffer_id != selection.start.buffer_id
 3695                    || s.end.buffer_id != selection.end.buffer_id
 3696                {
 3697                    return false;
 3698                }
 3699                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3700                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3701            }) {
 3702                continue;
 3703            }
 3704            let start = buffer_snapshot.anchor_after(start_offset);
 3705            let end = buffer_snapshot.anchor_after(end_offset);
 3706            linked_edits
 3707                .entry(buffer.clone())
 3708                .or_default()
 3709                .push(start..end);
 3710        }
 3711        Some(linked_edits)
 3712    }
 3713
 3714    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3715        let text: Arc<str> = text.into();
 3716
 3717        if self.read_only(cx) {
 3718            return;
 3719        }
 3720
 3721        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3722
 3723        let selections = self.selections.all_adjusted(cx);
 3724        let mut bracket_inserted = false;
 3725        let mut edits = Vec::new();
 3726        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3727        let mut new_selections = Vec::with_capacity(selections.len());
 3728        let mut new_autoclose_regions = Vec::new();
 3729        let snapshot = self.buffer.read(cx).read(cx);
 3730        let mut clear_linked_edit_ranges = false;
 3731
 3732        for (selection, autoclose_region) in
 3733            self.selections_with_autoclose_regions(selections, &snapshot)
 3734        {
 3735            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3736                // Determine if the inserted text matches the opening or closing
 3737                // bracket of any of this language's bracket pairs.
 3738                let mut bracket_pair = None;
 3739                let mut is_bracket_pair_start = false;
 3740                let mut is_bracket_pair_end = false;
 3741                if !text.is_empty() {
 3742                    let mut bracket_pair_matching_end = None;
 3743                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3744                    //  and they are removing the character that triggered IME popup.
 3745                    for (pair, enabled) in scope.brackets() {
 3746                        if !pair.close && !pair.surround {
 3747                            continue;
 3748                        }
 3749
 3750                        if enabled && pair.start.ends_with(text.as_ref()) {
 3751                            let prefix_len = pair.start.len() - text.len();
 3752                            let preceding_text_matches_prefix = prefix_len == 0
 3753                                || (selection.start.column >= (prefix_len as u32)
 3754                                    && snapshot.contains_str_at(
 3755                                        Point::new(
 3756                                            selection.start.row,
 3757                                            selection.start.column - (prefix_len as u32),
 3758                                        ),
 3759                                        &pair.start[..prefix_len],
 3760                                    ));
 3761                            if preceding_text_matches_prefix {
 3762                                bracket_pair = Some(pair.clone());
 3763                                is_bracket_pair_start = true;
 3764                                break;
 3765                            }
 3766                        }
 3767                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3768                        {
 3769                            // take first bracket pair matching end, but don't break in case a later bracket
 3770                            // pair matches start
 3771                            bracket_pair_matching_end = Some(pair.clone());
 3772                        }
 3773                    }
 3774                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3775                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3776                        is_bracket_pair_end = true;
 3777                    }
 3778                }
 3779
 3780                if let Some(bracket_pair) = bracket_pair {
 3781                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3782                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3783                    let auto_surround =
 3784                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3785                    if selection.is_empty() {
 3786                        if is_bracket_pair_start {
 3787                            // If the inserted text is a suffix of an opening bracket and the
 3788                            // selection is preceded by the rest of the opening bracket, then
 3789                            // insert the closing bracket.
 3790                            let following_text_allows_autoclose = snapshot
 3791                                .chars_at(selection.start)
 3792                                .next()
 3793                                .map_or(true, |c| scope.should_autoclose_before(c));
 3794
 3795                            let preceding_text_allows_autoclose = selection.start.column == 0
 3796                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3797                                    true,
 3798                                    |c| {
 3799                                        bracket_pair.start != bracket_pair.end
 3800                                            || !snapshot
 3801                                                .char_classifier_at(selection.start)
 3802                                                .is_word(c)
 3803                                    },
 3804                                );
 3805
 3806                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3807                                && bracket_pair.start.len() == 1
 3808                            {
 3809                                let target = bracket_pair.start.chars().next().unwrap();
 3810                                let current_line_count = snapshot
 3811                                    .reversed_chars_at(selection.start)
 3812                                    .take_while(|&c| c != '\n')
 3813                                    .filter(|&c| c == target)
 3814                                    .count();
 3815                                current_line_count % 2 == 1
 3816                            } else {
 3817                                false
 3818                            };
 3819
 3820                            if autoclose
 3821                                && bracket_pair.close
 3822                                && following_text_allows_autoclose
 3823                                && preceding_text_allows_autoclose
 3824                                && !is_closing_quote
 3825                            {
 3826                                let anchor = snapshot.anchor_before(selection.end);
 3827                                new_selections.push((selection.map(|_| anchor), text.len()));
 3828                                new_autoclose_regions.push((
 3829                                    anchor,
 3830                                    text.len(),
 3831                                    selection.id,
 3832                                    bracket_pair.clone(),
 3833                                ));
 3834                                edits.push((
 3835                                    selection.range(),
 3836                                    format!("{}{}", text, bracket_pair.end).into(),
 3837                                ));
 3838                                bracket_inserted = true;
 3839                                continue;
 3840                            }
 3841                        }
 3842
 3843                        if let Some(region) = autoclose_region {
 3844                            // If the selection is followed by an auto-inserted closing bracket,
 3845                            // then don't insert that closing bracket again; just move the selection
 3846                            // past the closing bracket.
 3847                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3848                                && text.as_ref() == region.pair.end.as_str();
 3849                            if should_skip {
 3850                                let anchor = snapshot.anchor_after(selection.end);
 3851                                new_selections
 3852                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3853                                continue;
 3854                            }
 3855                        }
 3856
 3857                        let always_treat_brackets_as_autoclosed = snapshot
 3858                            .language_settings_at(selection.start, cx)
 3859                            .always_treat_brackets_as_autoclosed;
 3860                        if always_treat_brackets_as_autoclosed
 3861                            && is_bracket_pair_end
 3862                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3863                        {
 3864                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3865                            // and the inserted text is a closing bracket and the selection is followed
 3866                            // by the closing bracket then move the selection past the closing bracket.
 3867                            let anchor = snapshot.anchor_after(selection.end);
 3868                            new_selections.push((selection.map(|_| anchor), text.len()));
 3869                            continue;
 3870                        }
 3871                    }
 3872                    // If an opening bracket is 1 character long and is typed while
 3873                    // text is selected, then surround that text with the bracket pair.
 3874                    else if auto_surround
 3875                        && bracket_pair.surround
 3876                        && is_bracket_pair_start
 3877                        && bracket_pair.start.chars().count() == 1
 3878                    {
 3879                        edits.push((selection.start..selection.start, text.clone()));
 3880                        edits.push((
 3881                            selection.end..selection.end,
 3882                            bracket_pair.end.as_str().into(),
 3883                        ));
 3884                        bracket_inserted = true;
 3885                        new_selections.push((
 3886                            Selection {
 3887                                id: selection.id,
 3888                                start: snapshot.anchor_after(selection.start),
 3889                                end: snapshot.anchor_before(selection.end),
 3890                                reversed: selection.reversed,
 3891                                goal: selection.goal,
 3892                            },
 3893                            0,
 3894                        ));
 3895                        continue;
 3896                    }
 3897                }
 3898            }
 3899
 3900            if self.auto_replace_emoji_shortcode
 3901                && selection.is_empty()
 3902                && text.as_ref().ends_with(':')
 3903            {
 3904                if let Some(possible_emoji_short_code) =
 3905                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3906                {
 3907                    if !possible_emoji_short_code.is_empty() {
 3908                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3909                            let emoji_shortcode_start = Point::new(
 3910                                selection.start.row,
 3911                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3912                            );
 3913
 3914                            // Remove shortcode from buffer
 3915                            edits.push((
 3916                                emoji_shortcode_start..selection.start,
 3917                                "".to_string().into(),
 3918                            ));
 3919                            new_selections.push((
 3920                                Selection {
 3921                                    id: selection.id,
 3922                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3923                                    end: snapshot.anchor_before(selection.start),
 3924                                    reversed: selection.reversed,
 3925                                    goal: selection.goal,
 3926                                },
 3927                                0,
 3928                            ));
 3929
 3930                            // Insert emoji
 3931                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3932                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3933                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3934
 3935                            continue;
 3936                        }
 3937                    }
 3938                }
 3939            }
 3940
 3941            // If not handling any auto-close operation, then just replace the selected
 3942            // text with the given input and move the selection to the end of the
 3943            // newly inserted text.
 3944            let anchor = snapshot.anchor_after(selection.end);
 3945            if !self.linked_edit_ranges.is_empty() {
 3946                let start_anchor = snapshot.anchor_before(selection.start);
 3947
 3948                let is_word_char = text.chars().next().map_or(true, |char| {
 3949                    let classifier = snapshot
 3950                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3951                        .ignore_punctuation(true);
 3952                    classifier.is_word(char)
 3953                });
 3954
 3955                if is_word_char {
 3956                    if let Some(ranges) = self
 3957                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3958                    {
 3959                        for (buffer, edits) in ranges {
 3960                            linked_edits
 3961                                .entry(buffer.clone())
 3962                                .or_default()
 3963                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3964                        }
 3965                    }
 3966                } else {
 3967                    clear_linked_edit_ranges = true;
 3968                }
 3969            }
 3970
 3971            new_selections.push((selection.map(|_| anchor), 0));
 3972            edits.push((selection.start..selection.end, text.clone()));
 3973        }
 3974
 3975        drop(snapshot);
 3976
 3977        self.transact(window, cx, |this, window, cx| {
 3978            if clear_linked_edit_ranges {
 3979                this.linked_edit_ranges.clear();
 3980            }
 3981            let initial_buffer_versions =
 3982                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3983
 3984            this.buffer.update(cx, |buffer, cx| {
 3985                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3986            });
 3987            for (buffer, edits) in linked_edits {
 3988                buffer.update(cx, |buffer, cx| {
 3989                    let snapshot = buffer.snapshot();
 3990                    let edits = edits
 3991                        .into_iter()
 3992                        .map(|(range, text)| {
 3993                            use text::ToPoint as TP;
 3994                            let end_point = TP::to_point(&range.end, &snapshot);
 3995                            let start_point = TP::to_point(&range.start, &snapshot);
 3996                            (start_point..end_point, text)
 3997                        })
 3998                        .sorted_by_key(|(range, _)| range.start);
 3999                    buffer.edit(edits, None, cx);
 4000                })
 4001            }
 4002            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4003            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4004            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4005            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4006                .zip(new_selection_deltas)
 4007                .map(|(selection, delta)| Selection {
 4008                    id: selection.id,
 4009                    start: selection.start + delta,
 4010                    end: selection.end + delta,
 4011                    reversed: selection.reversed,
 4012                    goal: SelectionGoal::None,
 4013                })
 4014                .collect::<Vec<_>>();
 4015
 4016            let mut i = 0;
 4017            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4018                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4019                let start = map.buffer_snapshot.anchor_before(position);
 4020                let end = map.buffer_snapshot.anchor_after(position);
 4021                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4022                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4023                        Ordering::Less => i += 1,
 4024                        Ordering::Greater => break,
 4025                        Ordering::Equal => {
 4026                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4027                                Ordering::Less => i += 1,
 4028                                Ordering::Equal => break,
 4029                                Ordering::Greater => break,
 4030                            }
 4031                        }
 4032                    }
 4033                }
 4034                this.autoclose_regions.insert(
 4035                    i,
 4036                    AutocloseRegion {
 4037                        selection_id,
 4038                        range: start..end,
 4039                        pair,
 4040                    },
 4041                );
 4042            }
 4043
 4044            let had_active_inline_completion = this.has_active_inline_completion();
 4045            this.change_selections(
 4046                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4047                window,
 4048                cx,
 4049                |s| s.select(new_selections),
 4050            );
 4051
 4052            if !bracket_inserted {
 4053                if let Some(on_type_format_task) =
 4054                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4055                {
 4056                    on_type_format_task.detach_and_log_err(cx);
 4057                }
 4058            }
 4059
 4060            let editor_settings = EditorSettings::get_global(cx);
 4061            if bracket_inserted
 4062                && (editor_settings.auto_signature_help
 4063                    || editor_settings.show_signature_help_after_edits)
 4064            {
 4065                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4066            }
 4067
 4068            let trigger_in_words =
 4069                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4070            if this.hard_wrap.is_some() {
 4071                let latest: Range<Point> = this.selections.newest(cx).range();
 4072                if latest.is_empty()
 4073                    && this
 4074                        .buffer()
 4075                        .read(cx)
 4076                        .snapshot(cx)
 4077                        .line_len(MultiBufferRow(latest.start.row))
 4078                        == latest.start.column
 4079                {
 4080                    this.rewrap_impl(
 4081                        RewrapOptions {
 4082                            override_language_settings: true,
 4083                            preserve_existing_whitespace: true,
 4084                        },
 4085                        cx,
 4086                    )
 4087                }
 4088            }
 4089            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4090            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4091            this.refresh_inline_completion(true, false, window, cx);
 4092            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4093        });
 4094    }
 4095
 4096    fn find_possible_emoji_shortcode_at_position(
 4097        snapshot: &MultiBufferSnapshot,
 4098        position: Point,
 4099    ) -> Option<String> {
 4100        let mut chars = Vec::new();
 4101        let mut found_colon = false;
 4102        for char in snapshot.reversed_chars_at(position).take(100) {
 4103            // Found a possible emoji shortcode in the middle of the buffer
 4104            if found_colon {
 4105                if char.is_whitespace() {
 4106                    chars.reverse();
 4107                    return Some(chars.iter().collect());
 4108                }
 4109                // If the previous character is not a whitespace, we are in the middle of a word
 4110                // and we only want to complete the shortcode if the word is made up of other emojis
 4111                let mut containing_word = String::new();
 4112                for ch in snapshot
 4113                    .reversed_chars_at(position)
 4114                    .skip(chars.len() + 1)
 4115                    .take(100)
 4116                {
 4117                    if ch.is_whitespace() {
 4118                        break;
 4119                    }
 4120                    containing_word.push(ch);
 4121                }
 4122                let containing_word = containing_word.chars().rev().collect::<String>();
 4123                if util::word_consists_of_emojis(containing_word.as_str()) {
 4124                    chars.reverse();
 4125                    return Some(chars.iter().collect());
 4126                }
 4127            }
 4128
 4129            if char.is_whitespace() || !char.is_ascii() {
 4130                return None;
 4131            }
 4132            if char == ':' {
 4133                found_colon = true;
 4134            } else {
 4135                chars.push(char);
 4136            }
 4137        }
 4138        // Found a possible emoji shortcode at the beginning of the buffer
 4139        chars.reverse();
 4140        Some(chars.iter().collect())
 4141    }
 4142
 4143    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4144        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4145        self.transact(window, cx, |this, window, cx| {
 4146            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4147                let selections = this.selections.all::<usize>(cx);
 4148                let multi_buffer = this.buffer.read(cx);
 4149                let buffer = multi_buffer.snapshot(cx);
 4150                selections
 4151                    .iter()
 4152                    .map(|selection| {
 4153                        let start_point = selection.start.to_point(&buffer);
 4154                        let mut existing_indent =
 4155                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4156                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4157                        let start = selection.start;
 4158                        let end = selection.end;
 4159                        let selection_is_empty = start == end;
 4160                        let language_scope = buffer.language_scope_at(start);
 4161                        let (
 4162                            comment_delimiter,
 4163                            doc_delimiter,
 4164                            insert_extra_newline,
 4165                            indent_on_newline,
 4166                            indent_on_extra_newline,
 4167                        ) = if let Some(language) = &language_scope {
 4168                            let mut insert_extra_newline =
 4169                                insert_extra_newline_brackets(&buffer, start..end, language)
 4170                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4171
 4172                            // Comment extension on newline is allowed only for cursor selections
 4173                            let comment_delimiter = maybe!({
 4174                                if !selection_is_empty {
 4175                                    return None;
 4176                                }
 4177
 4178                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4179                                    return None;
 4180                                }
 4181
 4182                                let delimiters = language.line_comment_prefixes();
 4183                                let max_len_of_delimiter =
 4184                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4185                                let (snapshot, range) =
 4186                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4187
 4188                                let num_of_whitespaces = snapshot
 4189                                    .chars_for_range(range.clone())
 4190                                    .take_while(|c| c.is_whitespace())
 4191                                    .count();
 4192                                let comment_candidate = snapshot
 4193                                    .chars_for_range(range)
 4194                                    .skip(num_of_whitespaces)
 4195                                    .take(max_len_of_delimiter)
 4196                                    .collect::<String>();
 4197                                let (delimiter, trimmed_len) = delimiters
 4198                                    .iter()
 4199                                    .filter_map(|delimiter| {
 4200                                        let prefix = delimiter.trim_end();
 4201                                        if comment_candidate.starts_with(prefix) {
 4202                                            Some((delimiter, prefix.len()))
 4203                                        } else {
 4204                                            None
 4205                                        }
 4206                                    })
 4207                                    .max_by_key(|(_, len)| *len)?;
 4208
 4209                                let cursor_is_placed_after_comment_marker =
 4210                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4211                                if cursor_is_placed_after_comment_marker {
 4212                                    Some(delimiter.clone())
 4213                                } else {
 4214                                    None
 4215                                }
 4216                            });
 4217
 4218                            let mut indent_on_newline = IndentSize::spaces(0);
 4219                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4220
 4221                            let doc_delimiter = maybe!({
 4222                                if !selection_is_empty {
 4223                                    return None;
 4224                                }
 4225
 4226                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4227                                    return None;
 4228                                }
 4229
 4230                                let DocumentationConfig {
 4231                                    start: start_tag,
 4232                                    end: end_tag,
 4233                                    prefix: delimiter,
 4234                                    tab_size: len,
 4235                                } = language.documentation()?;
 4236
 4237                                let is_within_block_comment = buffer
 4238                                    .language_scope_at(start_point)
 4239                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4240                                if !is_within_block_comment {
 4241                                    return None;
 4242                                }
 4243
 4244                                let (snapshot, range) =
 4245                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4246
 4247                                let num_of_whitespaces = snapshot
 4248                                    .chars_for_range(range.clone())
 4249                                    .take_while(|c| c.is_whitespace())
 4250                                    .count();
 4251
 4252                                // 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.
 4253                                let column = start_point.column;
 4254                                let cursor_is_after_start_tag = {
 4255                                    let start_tag_len = start_tag.len();
 4256                                    let start_tag_line = snapshot
 4257                                        .chars_for_range(range.clone())
 4258                                        .skip(num_of_whitespaces)
 4259                                        .take(start_tag_len)
 4260                                        .collect::<String>();
 4261                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4262                                        num_of_whitespaces + start_tag_len <= column as usize
 4263                                    } else {
 4264                                        false
 4265                                    }
 4266                                };
 4267
 4268                                let cursor_is_after_delimiter = {
 4269                                    let delimiter_trim = delimiter.trim_end();
 4270                                    let delimiter_line = snapshot
 4271                                        .chars_for_range(range.clone())
 4272                                        .skip(num_of_whitespaces)
 4273                                        .take(delimiter_trim.len())
 4274                                        .collect::<String>();
 4275                                    if delimiter_line.starts_with(delimiter_trim) {
 4276                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4277                                    } else {
 4278                                        false
 4279                                    }
 4280                                };
 4281
 4282                                let cursor_is_before_end_tag_if_exists = {
 4283                                    let mut char_position = 0u32;
 4284                                    let mut end_tag_offset = None;
 4285
 4286                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4287                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4288                                            let chars_before_match =
 4289                                                chunk[..byte_pos].chars().count() as u32;
 4290                                            end_tag_offset =
 4291                                                Some(char_position + chars_before_match);
 4292                                            break 'outer;
 4293                                        }
 4294                                        char_position += chunk.chars().count() as u32;
 4295                                    }
 4296
 4297                                    if let Some(end_tag_offset) = end_tag_offset {
 4298                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4299                                        if cursor_is_after_start_tag {
 4300                                            if cursor_is_before_end_tag {
 4301                                                insert_extra_newline = true;
 4302                                            }
 4303                                            let cursor_is_at_start_of_end_tag =
 4304                                                column == end_tag_offset;
 4305                                            if cursor_is_at_start_of_end_tag {
 4306                                                indent_on_extra_newline.len = (*len).into();
 4307                                            }
 4308                                        }
 4309                                        cursor_is_before_end_tag
 4310                                    } else {
 4311                                        true
 4312                                    }
 4313                                };
 4314
 4315                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4316                                    && cursor_is_before_end_tag_if_exists
 4317                                {
 4318                                    if cursor_is_after_start_tag {
 4319                                        indent_on_newline.len = (*len).into();
 4320                                    }
 4321                                    Some(delimiter.clone())
 4322                                } else {
 4323                                    None
 4324                                }
 4325                            });
 4326
 4327                            (
 4328                                comment_delimiter,
 4329                                doc_delimiter,
 4330                                insert_extra_newline,
 4331                                indent_on_newline,
 4332                                indent_on_extra_newline,
 4333                            )
 4334                        } else {
 4335                            (
 4336                                None,
 4337                                None,
 4338                                false,
 4339                                IndentSize::default(),
 4340                                IndentSize::default(),
 4341                            )
 4342                        };
 4343
 4344                        let prevent_auto_indent = doc_delimiter.is_some();
 4345                        let delimiter = comment_delimiter.or(doc_delimiter);
 4346
 4347                        let capacity_for_delimiter =
 4348                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4349                        let mut new_text = String::with_capacity(
 4350                            1 + capacity_for_delimiter
 4351                                + existing_indent.len as usize
 4352                                + indent_on_newline.len as usize
 4353                                + indent_on_extra_newline.len as usize,
 4354                        );
 4355                        new_text.push('\n');
 4356                        new_text.extend(existing_indent.chars());
 4357                        new_text.extend(indent_on_newline.chars());
 4358
 4359                        if let Some(delimiter) = &delimiter {
 4360                            new_text.push_str(delimiter);
 4361                        }
 4362
 4363                        if insert_extra_newline {
 4364                            new_text.push('\n');
 4365                            new_text.extend(existing_indent.chars());
 4366                            new_text.extend(indent_on_extra_newline.chars());
 4367                        }
 4368
 4369                        let anchor = buffer.anchor_after(end);
 4370                        let new_selection = selection.map(|_| anchor);
 4371                        (
 4372                            ((start..end, new_text), prevent_auto_indent),
 4373                            (insert_extra_newline, new_selection),
 4374                        )
 4375                    })
 4376                    .unzip()
 4377            };
 4378
 4379            let mut auto_indent_edits = Vec::new();
 4380            let mut edits = Vec::new();
 4381            for (edit, prevent_auto_indent) in edits_with_flags {
 4382                if prevent_auto_indent {
 4383                    edits.push(edit);
 4384                } else {
 4385                    auto_indent_edits.push(edit);
 4386                }
 4387            }
 4388            if !edits.is_empty() {
 4389                this.edit(edits, cx);
 4390            }
 4391            if !auto_indent_edits.is_empty() {
 4392                this.edit_with_autoindent(auto_indent_edits, cx);
 4393            }
 4394
 4395            let buffer = this.buffer.read(cx).snapshot(cx);
 4396            let new_selections = selection_info
 4397                .into_iter()
 4398                .map(|(extra_newline_inserted, new_selection)| {
 4399                    let mut cursor = new_selection.end.to_point(&buffer);
 4400                    if extra_newline_inserted {
 4401                        cursor.row -= 1;
 4402                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4403                    }
 4404                    new_selection.map(|_| cursor)
 4405                })
 4406                .collect();
 4407
 4408            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4409                s.select(new_selections)
 4410            });
 4411            this.refresh_inline_completion(true, false, window, cx);
 4412        });
 4413    }
 4414
 4415    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4416        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4417
 4418        let buffer = self.buffer.read(cx);
 4419        let snapshot = buffer.snapshot(cx);
 4420
 4421        let mut edits = Vec::new();
 4422        let mut rows = Vec::new();
 4423
 4424        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4425            let cursor = selection.head();
 4426            let row = cursor.row;
 4427
 4428            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4429
 4430            let newline = "\n".to_string();
 4431            edits.push((start_of_line..start_of_line, newline));
 4432
 4433            rows.push(row + rows_inserted as u32);
 4434        }
 4435
 4436        self.transact(window, cx, |editor, window, cx| {
 4437            editor.edit(edits, cx);
 4438
 4439            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4440                let mut index = 0;
 4441                s.move_cursors_with(|map, _, _| {
 4442                    let row = rows[index];
 4443                    index += 1;
 4444
 4445                    let point = Point::new(row, 0);
 4446                    let boundary = map.next_line_boundary(point).1;
 4447                    let clipped = map.clip_point(boundary, Bias::Left);
 4448
 4449                    (clipped, SelectionGoal::None)
 4450                });
 4451            });
 4452
 4453            let mut indent_edits = Vec::new();
 4454            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4455            for row in rows {
 4456                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4457                for (row, indent) in indents {
 4458                    if indent.len == 0 {
 4459                        continue;
 4460                    }
 4461
 4462                    let text = match indent.kind {
 4463                        IndentKind::Space => " ".repeat(indent.len as usize),
 4464                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4465                    };
 4466                    let point = Point::new(row.0, 0);
 4467                    indent_edits.push((point..point, text));
 4468                }
 4469            }
 4470            editor.edit(indent_edits, cx);
 4471        });
 4472    }
 4473
 4474    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4475        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4476
 4477        let buffer = self.buffer.read(cx);
 4478        let snapshot = buffer.snapshot(cx);
 4479
 4480        let mut edits = Vec::new();
 4481        let mut rows = Vec::new();
 4482        let mut rows_inserted = 0;
 4483
 4484        for selection in self.selections.all_adjusted(cx) {
 4485            let cursor = selection.head();
 4486            let row = cursor.row;
 4487
 4488            let point = Point::new(row + 1, 0);
 4489            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4490
 4491            let newline = "\n".to_string();
 4492            edits.push((start_of_line..start_of_line, newline));
 4493
 4494            rows_inserted += 1;
 4495            rows.push(row + rows_inserted);
 4496        }
 4497
 4498        self.transact(window, cx, |editor, window, cx| {
 4499            editor.edit(edits, cx);
 4500
 4501            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4502                let mut index = 0;
 4503                s.move_cursors_with(|map, _, _| {
 4504                    let row = rows[index];
 4505                    index += 1;
 4506
 4507                    let point = Point::new(row, 0);
 4508                    let boundary = map.next_line_boundary(point).1;
 4509                    let clipped = map.clip_point(boundary, Bias::Left);
 4510
 4511                    (clipped, SelectionGoal::None)
 4512                });
 4513            });
 4514
 4515            let mut indent_edits = Vec::new();
 4516            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4517            for row in rows {
 4518                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4519                for (row, indent) in indents {
 4520                    if indent.len == 0 {
 4521                        continue;
 4522                    }
 4523
 4524                    let text = match indent.kind {
 4525                        IndentKind::Space => " ".repeat(indent.len as usize),
 4526                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4527                    };
 4528                    let point = Point::new(row.0, 0);
 4529                    indent_edits.push((point..point, text));
 4530                }
 4531            }
 4532            editor.edit(indent_edits, cx);
 4533        });
 4534    }
 4535
 4536    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4537        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4538            original_indent_columns: Vec::new(),
 4539        });
 4540        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4541    }
 4542
 4543    fn insert_with_autoindent_mode(
 4544        &mut self,
 4545        text: &str,
 4546        autoindent_mode: Option<AutoindentMode>,
 4547        window: &mut Window,
 4548        cx: &mut Context<Self>,
 4549    ) {
 4550        if self.read_only(cx) {
 4551            return;
 4552        }
 4553
 4554        let text: Arc<str> = text.into();
 4555        self.transact(window, cx, |this, window, cx| {
 4556            let old_selections = this.selections.all_adjusted(cx);
 4557            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4558                let anchors = {
 4559                    let snapshot = buffer.read(cx);
 4560                    old_selections
 4561                        .iter()
 4562                        .map(|s| {
 4563                            let anchor = snapshot.anchor_after(s.head());
 4564                            s.map(|_| anchor)
 4565                        })
 4566                        .collect::<Vec<_>>()
 4567                };
 4568                buffer.edit(
 4569                    old_selections
 4570                        .iter()
 4571                        .map(|s| (s.start..s.end, text.clone())),
 4572                    autoindent_mode,
 4573                    cx,
 4574                );
 4575                anchors
 4576            });
 4577
 4578            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4579                s.select_anchors(selection_anchors);
 4580            });
 4581
 4582            cx.notify();
 4583        });
 4584    }
 4585
 4586    fn trigger_completion_on_input(
 4587        &mut self,
 4588        text: &str,
 4589        trigger_in_words: bool,
 4590        window: &mut Window,
 4591        cx: &mut Context<Self>,
 4592    ) {
 4593        let completions_source = self
 4594            .context_menu
 4595            .borrow()
 4596            .as_ref()
 4597            .and_then(|menu| match menu {
 4598                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4599                CodeContextMenu::CodeActions(_) => None,
 4600            });
 4601
 4602        match completions_source {
 4603            Some(CompletionsMenuSource::Words) => {
 4604                self.show_word_completions(&ShowWordCompletions, window, cx)
 4605            }
 4606            Some(CompletionsMenuSource::Normal)
 4607            | Some(CompletionsMenuSource::SnippetChoices)
 4608            | None
 4609                if self.is_completion_trigger(
 4610                    text,
 4611                    trigger_in_words,
 4612                    completions_source.is_some(),
 4613                    cx,
 4614                ) =>
 4615            {
 4616                self.show_completions(
 4617                    &ShowCompletions {
 4618                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4619                    },
 4620                    window,
 4621                    cx,
 4622                )
 4623            }
 4624            _ => {
 4625                self.hide_context_menu(window, cx);
 4626            }
 4627        }
 4628    }
 4629
 4630    fn is_completion_trigger(
 4631        &self,
 4632        text: &str,
 4633        trigger_in_words: bool,
 4634        menu_is_open: bool,
 4635        cx: &mut Context<Self>,
 4636    ) -> bool {
 4637        let position = self.selections.newest_anchor().head();
 4638        let multibuffer = self.buffer.read(cx);
 4639        let Some(buffer) = position
 4640            .buffer_id
 4641            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4642        else {
 4643            return false;
 4644        };
 4645
 4646        if let Some(completion_provider) = &self.completion_provider {
 4647            completion_provider.is_completion_trigger(
 4648                &buffer,
 4649                position.text_anchor,
 4650                text,
 4651                trigger_in_words,
 4652                menu_is_open,
 4653                cx,
 4654            )
 4655        } else {
 4656            false
 4657        }
 4658    }
 4659
 4660    /// If any empty selections is touching the start of its innermost containing autoclose
 4661    /// region, expand it to select the brackets.
 4662    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4663        let selections = self.selections.all::<usize>(cx);
 4664        let buffer = self.buffer.read(cx).read(cx);
 4665        let new_selections = self
 4666            .selections_with_autoclose_regions(selections, &buffer)
 4667            .map(|(mut selection, region)| {
 4668                if !selection.is_empty() {
 4669                    return selection;
 4670                }
 4671
 4672                if let Some(region) = region {
 4673                    let mut range = region.range.to_offset(&buffer);
 4674                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4675                        range.start -= region.pair.start.len();
 4676                        if buffer.contains_str_at(range.start, &region.pair.start)
 4677                            && buffer.contains_str_at(range.end, &region.pair.end)
 4678                        {
 4679                            range.end += region.pair.end.len();
 4680                            selection.start = range.start;
 4681                            selection.end = range.end;
 4682
 4683                            return selection;
 4684                        }
 4685                    }
 4686                }
 4687
 4688                let always_treat_brackets_as_autoclosed = buffer
 4689                    .language_settings_at(selection.start, cx)
 4690                    .always_treat_brackets_as_autoclosed;
 4691
 4692                if !always_treat_brackets_as_autoclosed {
 4693                    return selection;
 4694                }
 4695
 4696                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4697                    for (pair, enabled) in scope.brackets() {
 4698                        if !enabled || !pair.close {
 4699                            continue;
 4700                        }
 4701
 4702                        if buffer.contains_str_at(selection.start, &pair.end) {
 4703                            let pair_start_len = pair.start.len();
 4704                            if buffer.contains_str_at(
 4705                                selection.start.saturating_sub(pair_start_len),
 4706                                &pair.start,
 4707                            ) {
 4708                                selection.start -= pair_start_len;
 4709                                selection.end += pair.end.len();
 4710
 4711                                return selection;
 4712                            }
 4713                        }
 4714                    }
 4715                }
 4716
 4717                selection
 4718            })
 4719            .collect();
 4720
 4721        drop(buffer);
 4722        self.change_selections(None, window, cx, |selections| {
 4723            selections.select(new_selections)
 4724        });
 4725    }
 4726
 4727    /// Iterate the given selections, and for each one, find the smallest surrounding
 4728    /// autoclose region. This uses the ordering of the selections and the autoclose
 4729    /// regions to avoid repeated comparisons.
 4730    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4731        &'a self,
 4732        selections: impl IntoIterator<Item = Selection<D>>,
 4733        buffer: &'a MultiBufferSnapshot,
 4734    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4735        let mut i = 0;
 4736        let mut regions = self.autoclose_regions.as_slice();
 4737        selections.into_iter().map(move |selection| {
 4738            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4739
 4740            let mut enclosing = None;
 4741            while let Some(pair_state) = regions.get(i) {
 4742                if pair_state.range.end.to_offset(buffer) < range.start {
 4743                    regions = &regions[i + 1..];
 4744                    i = 0;
 4745                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4746                    break;
 4747                } else {
 4748                    if pair_state.selection_id == selection.id {
 4749                        enclosing = Some(pair_state);
 4750                    }
 4751                    i += 1;
 4752                }
 4753            }
 4754
 4755            (selection, enclosing)
 4756        })
 4757    }
 4758
 4759    /// Remove any autoclose regions that no longer contain their selection.
 4760    fn invalidate_autoclose_regions(
 4761        &mut self,
 4762        mut selections: &[Selection<Anchor>],
 4763        buffer: &MultiBufferSnapshot,
 4764    ) {
 4765        self.autoclose_regions.retain(|state| {
 4766            let mut i = 0;
 4767            while let Some(selection) = selections.get(i) {
 4768                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4769                    selections = &selections[1..];
 4770                    continue;
 4771                }
 4772                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4773                    break;
 4774                }
 4775                if selection.id == state.selection_id {
 4776                    return true;
 4777                } else {
 4778                    i += 1;
 4779                }
 4780            }
 4781            false
 4782        });
 4783    }
 4784
 4785    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4786        let offset = position.to_offset(buffer);
 4787        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4788        if offset > word_range.start && kind == Some(CharKind::Word) {
 4789            Some(
 4790                buffer
 4791                    .text_for_range(word_range.start..offset)
 4792                    .collect::<String>(),
 4793            )
 4794        } else {
 4795            None
 4796        }
 4797    }
 4798
 4799    pub fn toggle_inline_values(
 4800        &mut self,
 4801        _: &ToggleInlineValues,
 4802        _: &mut Window,
 4803        cx: &mut Context<Self>,
 4804    ) {
 4805        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4806
 4807        self.refresh_inline_values(cx);
 4808    }
 4809
 4810    pub fn toggle_inlay_hints(
 4811        &mut self,
 4812        _: &ToggleInlayHints,
 4813        _: &mut Window,
 4814        cx: &mut Context<Self>,
 4815    ) {
 4816        self.refresh_inlay_hints(
 4817            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4818            cx,
 4819        );
 4820    }
 4821
 4822    pub fn inlay_hints_enabled(&self) -> bool {
 4823        self.inlay_hint_cache.enabled
 4824    }
 4825
 4826    pub fn inline_values_enabled(&self) -> bool {
 4827        self.inline_value_cache.enabled
 4828    }
 4829
 4830    #[cfg(any(test, feature = "test-support"))]
 4831    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4832        self.display_map
 4833            .read(cx)
 4834            .current_inlays()
 4835            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4836            .cloned()
 4837            .collect()
 4838    }
 4839
 4840    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4841        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4842            return;
 4843        }
 4844
 4845        let reason_description = reason.description();
 4846        let ignore_debounce = matches!(
 4847            reason,
 4848            InlayHintRefreshReason::SettingsChange(_)
 4849                | InlayHintRefreshReason::Toggle(_)
 4850                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4851                | InlayHintRefreshReason::ModifiersChanged(_)
 4852        );
 4853        let (invalidate_cache, required_languages) = match reason {
 4854            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4855                match self.inlay_hint_cache.modifiers_override(enabled) {
 4856                    Some(enabled) => {
 4857                        if enabled {
 4858                            (InvalidationStrategy::RefreshRequested, None)
 4859                        } else {
 4860                            self.splice_inlays(
 4861                                &self
 4862                                    .visible_inlay_hints(cx)
 4863                                    .iter()
 4864                                    .map(|inlay| inlay.id)
 4865                                    .collect::<Vec<InlayId>>(),
 4866                                Vec::new(),
 4867                                cx,
 4868                            );
 4869                            return;
 4870                        }
 4871                    }
 4872                    None => return,
 4873                }
 4874            }
 4875            InlayHintRefreshReason::Toggle(enabled) => {
 4876                if self.inlay_hint_cache.toggle(enabled) {
 4877                    if enabled {
 4878                        (InvalidationStrategy::RefreshRequested, None)
 4879                    } else {
 4880                        self.splice_inlays(
 4881                            &self
 4882                                .visible_inlay_hints(cx)
 4883                                .iter()
 4884                                .map(|inlay| inlay.id)
 4885                                .collect::<Vec<InlayId>>(),
 4886                            Vec::new(),
 4887                            cx,
 4888                        );
 4889                        return;
 4890                    }
 4891                } else {
 4892                    return;
 4893                }
 4894            }
 4895            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4896                match self.inlay_hint_cache.update_settings(
 4897                    &self.buffer,
 4898                    new_settings,
 4899                    self.visible_inlay_hints(cx),
 4900                    cx,
 4901                ) {
 4902                    ControlFlow::Break(Some(InlaySplice {
 4903                        to_remove,
 4904                        to_insert,
 4905                    })) => {
 4906                        self.splice_inlays(&to_remove, to_insert, cx);
 4907                        return;
 4908                    }
 4909                    ControlFlow::Break(None) => return,
 4910                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4911                }
 4912            }
 4913            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4914                if let Some(InlaySplice {
 4915                    to_remove,
 4916                    to_insert,
 4917                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4918                {
 4919                    self.splice_inlays(&to_remove, to_insert, cx);
 4920                }
 4921                self.display_map.update(cx, |display_map, _| {
 4922                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4923                });
 4924                return;
 4925            }
 4926            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4927            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4928                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4929            }
 4930            InlayHintRefreshReason::RefreshRequested => {
 4931                (InvalidationStrategy::RefreshRequested, None)
 4932            }
 4933        };
 4934
 4935        if let Some(InlaySplice {
 4936            to_remove,
 4937            to_insert,
 4938        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4939            reason_description,
 4940            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4941            invalidate_cache,
 4942            ignore_debounce,
 4943            cx,
 4944        ) {
 4945            self.splice_inlays(&to_remove, to_insert, cx);
 4946        }
 4947    }
 4948
 4949    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4950        self.display_map
 4951            .read(cx)
 4952            .current_inlays()
 4953            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4954            .cloned()
 4955            .collect()
 4956    }
 4957
 4958    pub fn excerpts_for_inlay_hints_query(
 4959        &self,
 4960        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4961        cx: &mut Context<Editor>,
 4962    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4963        let Some(project) = self.project.as_ref() else {
 4964            return HashMap::default();
 4965        };
 4966        let project = project.read(cx);
 4967        let multi_buffer = self.buffer().read(cx);
 4968        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4969        let multi_buffer_visible_start = self
 4970            .scroll_manager
 4971            .anchor()
 4972            .anchor
 4973            .to_point(&multi_buffer_snapshot);
 4974        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4975            multi_buffer_visible_start
 4976                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4977            Bias::Left,
 4978        );
 4979        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4980        multi_buffer_snapshot
 4981            .range_to_buffer_ranges(multi_buffer_visible_range)
 4982            .into_iter()
 4983            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4984            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4985                let buffer_file = project::File::from_dyn(buffer.file())?;
 4986                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4987                let worktree_entry = buffer_worktree
 4988                    .read(cx)
 4989                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4990                if worktree_entry.is_ignored {
 4991                    return None;
 4992                }
 4993
 4994                let language = buffer.language()?;
 4995                if let Some(restrict_to_languages) = restrict_to_languages {
 4996                    if !restrict_to_languages.contains(language) {
 4997                        return None;
 4998                    }
 4999                }
 5000                Some((
 5001                    excerpt_id,
 5002                    (
 5003                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5004                        buffer.version().clone(),
 5005                        excerpt_visible_range,
 5006                    ),
 5007                ))
 5008            })
 5009            .collect()
 5010    }
 5011
 5012    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5013        TextLayoutDetails {
 5014            text_system: window.text_system().clone(),
 5015            editor_style: self.style.clone().unwrap(),
 5016            rem_size: window.rem_size(),
 5017            scroll_anchor: self.scroll_manager.anchor(),
 5018            visible_rows: self.visible_line_count(),
 5019            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5020        }
 5021    }
 5022
 5023    pub fn splice_inlays(
 5024        &self,
 5025        to_remove: &[InlayId],
 5026        to_insert: Vec<Inlay>,
 5027        cx: &mut Context<Self>,
 5028    ) {
 5029        self.display_map.update(cx, |display_map, cx| {
 5030            display_map.splice_inlays(to_remove, to_insert, cx)
 5031        });
 5032        cx.notify();
 5033    }
 5034
 5035    fn trigger_on_type_formatting(
 5036        &self,
 5037        input: String,
 5038        window: &mut Window,
 5039        cx: &mut Context<Self>,
 5040    ) -> Option<Task<Result<()>>> {
 5041        if input.len() != 1 {
 5042            return None;
 5043        }
 5044
 5045        let project = self.project.as_ref()?;
 5046        let position = self.selections.newest_anchor().head();
 5047        let (buffer, buffer_position) = self
 5048            .buffer
 5049            .read(cx)
 5050            .text_anchor_for_position(position, cx)?;
 5051
 5052        let settings = language_settings::language_settings(
 5053            buffer
 5054                .read(cx)
 5055                .language_at(buffer_position)
 5056                .map(|l| l.name()),
 5057            buffer.read(cx).file(),
 5058            cx,
 5059        );
 5060        if !settings.use_on_type_format {
 5061            return None;
 5062        }
 5063
 5064        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5065        // hence we do LSP request & edit on host side only — add formats to host's history.
 5066        let push_to_lsp_host_history = true;
 5067        // If this is not the host, append its history with new edits.
 5068        let push_to_client_history = project.read(cx).is_via_collab();
 5069
 5070        let on_type_formatting = project.update(cx, |project, cx| {
 5071            project.on_type_format(
 5072                buffer.clone(),
 5073                buffer_position,
 5074                input,
 5075                push_to_lsp_host_history,
 5076                cx,
 5077            )
 5078        });
 5079        Some(cx.spawn_in(window, async move |editor, cx| {
 5080            if let Some(transaction) = on_type_formatting.await? {
 5081                if push_to_client_history {
 5082                    buffer
 5083                        .update(cx, |buffer, _| {
 5084                            buffer.push_transaction(transaction, Instant::now());
 5085                            buffer.finalize_last_transaction();
 5086                        })
 5087                        .ok();
 5088                }
 5089                editor.update(cx, |editor, cx| {
 5090                    editor.refresh_document_highlights(cx);
 5091                })?;
 5092            }
 5093            Ok(())
 5094        }))
 5095    }
 5096
 5097    pub fn show_word_completions(
 5098        &mut self,
 5099        _: &ShowWordCompletions,
 5100        window: &mut Window,
 5101        cx: &mut Context<Self>,
 5102    ) {
 5103        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5104    }
 5105
 5106    pub fn show_completions(
 5107        &mut self,
 5108        options: &ShowCompletions,
 5109        window: &mut Window,
 5110        cx: &mut Context<Self>,
 5111    ) {
 5112        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5113    }
 5114
 5115    fn open_or_update_completions_menu(
 5116        &mut self,
 5117        requested_source: Option<CompletionsMenuSource>,
 5118        trigger: Option<&str>,
 5119        window: &mut Window,
 5120        cx: &mut Context<Self>,
 5121    ) {
 5122        if self.pending_rename.is_some() {
 5123            return;
 5124        }
 5125
 5126        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5127
 5128        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5129        // inserted and selected. To handle that case, the start of the selection is used so that
 5130        // the menu starts with all choices.
 5131        let position = self
 5132            .selections
 5133            .newest_anchor()
 5134            .start
 5135            .bias_right(&multibuffer_snapshot);
 5136        if position.diff_base_anchor.is_some() {
 5137            return;
 5138        }
 5139        let (buffer, buffer_position) =
 5140            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5141                output
 5142            } else {
 5143                return;
 5144            };
 5145        let buffer_snapshot = buffer.read(cx).snapshot();
 5146
 5147        let query: Option<Arc<String>> =
 5148            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5149
 5150        drop(multibuffer_snapshot);
 5151
 5152        let provider = match requested_source {
 5153            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5154            Some(CompletionsMenuSource::Words) => None,
 5155            Some(CompletionsMenuSource::SnippetChoices) => {
 5156                log::error!("bug: SnippetChoices requested_source is not handled");
 5157                None
 5158            }
 5159        };
 5160
 5161        let sort_completions = provider
 5162            .as_ref()
 5163            .map_or(false, |provider| provider.sort_completions());
 5164
 5165        let filter_completions = provider
 5166            .as_ref()
 5167            .map_or(true, |provider| provider.filter_completions());
 5168
 5169        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5170            if filter_completions {
 5171                menu.filter(query.clone(), provider.clone(), window, cx);
 5172            }
 5173            // When `is_incomplete` is false, no need to re-query completions when the current query
 5174            // is a suffix of the initial query.
 5175            if !menu.is_incomplete {
 5176                // If the new query is a suffix of the old query (typing more characters) and
 5177                // the previous result was complete, the existing completions can be filtered.
 5178                //
 5179                // Note that this is always true for snippet completions.
 5180                let query_matches = match (&menu.initial_query, &query) {
 5181                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5182                    (None, _) => true,
 5183                    _ => false,
 5184                };
 5185                if query_matches {
 5186                    let position_matches = if menu.initial_position == position {
 5187                        true
 5188                    } else {
 5189                        let snapshot = self.buffer.read(cx).read(cx);
 5190                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5191                    };
 5192                    if position_matches {
 5193                        return;
 5194                    }
 5195                }
 5196            }
 5197        };
 5198
 5199        let trigger_kind = match trigger {
 5200            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5201                CompletionTriggerKind::TRIGGER_CHARACTER
 5202            }
 5203            _ => CompletionTriggerKind::INVOKED,
 5204        };
 5205        let completion_context = CompletionContext {
 5206            trigger_character: trigger.and_then(|trigger| {
 5207                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5208                    Some(String::from(trigger))
 5209                } else {
 5210                    None
 5211                }
 5212            }),
 5213            trigger_kind,
 5214        };
 5215
 5216        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5217            buffer_snapshot.surrounding_word(buffer_position)
 5218        {
 5219            let word_to_exclude = buffer_snapshot
 5220                .text_for_range(word_range.clone())
 5221                .collect::<String>();
 5222            (
 5223                buffer_snapshot.anchor_before(word_range.start)
 5224                    ..buffer_snapshot.anchor_after(buffer_position),
 5225                Some(word_to_exclude),
 5226            )
 5227        } else {
 5228            (buffer_position..buffer_position, None)
 5229        };
 5230
 5231        let language = buffer_snapshot
 5232            .language_at(buffer_position)
 5233            .map(|language| language.name());
 5234
 5235        let completion_settings =
 5236            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5237
 5238        let show_completion_documentation = buffer_snapshot
 5239            .settings_at(buffer_position, cx)
 5240            .show_completion_documentation;
 5241
 5242        // The document can be large, so stay in reasonable bounds when searching for words,
 5243        // otherwise completion pop-up might be slow to appear.
 5244        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5245        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5246        let min_word_search = buffer_snapshot.clip_point(
 5247            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5248            Bias::Left,
 5249        );
 5250        let max_word_search = buffer_snapshot.clip_point(
 5251            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5252            Bias::Right,
 5253        );
 5254        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5255            ..buffer_snapshot.point_to_offset(max_word_search);
 5256
 5257        let skip_digits = query
 5258            .as_ref()
 5259            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5260
 5261        let (mut words, provider_responses) = match &provider {
 5262            Some(provider) => {
 5263                let provider_responses = provider.completions(
 5264                    position.excerpt_id,
 5265                    &buffer,
 5266                    buffer_position,
 5267                    completion_context,
 5268                    window,
 5269                    cx,
 5270                );
 5271
 5272                let words = match completion_settings.words {
 5273                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5274                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5275                        .background_spawn(async move {
 5276                            buffer_snapshot.words_in_range(WordsQuery {
 5277                                fuzzy_contents: None,
 5278                                range: word_search_range,
 5279                                skip_digits,
 5280                            })
 5281                        }),
 5282                };
 5283
 5284                (words, provider_responses)
 5285            }
 5286            None => (
 5287                cx.background_spawn(async move {
 5288                    buffer_snapshot.words_in_range(WordsQuery {
 5289                        fuzzy_contents: None,
 5290                        range: word_search_range,
 5291                        skip_digits,
 5292                    })
 5293                }),
 5294                Task::ready(Ok(Vec::new())),
 5295            ),
 5296        };
 5297
 5298        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5299
 5300        let id = post_inc(&mut self.next_completion_id);
 5301        let task = cx.spawn_in(window, async move |editor, cx| {
 5302            let Ok(()) = editor.update(cx, |this, _| {
 5303                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5304            }) else {
 5305                return;
 5306            };
 5307
 5308            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5309            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5310            let mut completions = Vec::new();
 5311            let mut is_incomplete = false;
 5312            if let Some(provider_responses) = provider_responses.await.log_err() {
 5313                if !provider_responses.is_empty() {
 5314                    for response in provider_responses {
 5315                        completions.extend(response.completions);
 5316                        is_incomplete = is_incomplete || response.is_incomplete;
 5317                    }
 5318                    if completion_settings.words == WordsCompletionMode::Fallback {
 5319                        words = Task::ready(BTreeMap::default());
 5320                    }
 5321                }
 5322            }
 5323
 5324            let mut words = words.await;
 5325            if let Some(word_to_exclude) = &word_to_exclude {
 5326                words.remove(word_to_exclude);
 5327            }
 5328            for lsp_completion in &completions {
 5329                words.remove(&lsp_completion.new_text);
 5330            }
 5331            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5332                replace_range: word_replace_range.clone(),
 5333                new_text: word.clone(),
 5334                label: CodeLabel::plain(word, None),
 5335                icon_path: None,
 5336                documentation: None,
 5337                source: CompletionSource::BufferWord {
 5338                    word_range,
 5339                    resolved: false,
 5340                },
 5341                insert_text_mode: Some(InsertTextMode::AS_IS),
 5342                confirm: None,
 5343            }));
 5344
 5345            let menu = if completions.is_empty() {
 5346                None
 5347            } else {
 5348                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5349                    let languages = editor
 5350                        .workspace
 5351                        .as_ref()
 5352                        .and_then(|(workspace, _)| workspace.upgrade())
 5353                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5354                    let menu = CompletionsMenu::new(
 5355                        id,
 5356                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5357                        sort_completions,
 5358                        show_completion_documentation,
 5359                        position,
 5360                        query.clone(),
 5361                        is_incomplete,
 5362                        buffer.clone(),
 5363                        completions.into(),
 5364                        snippet_sort_order,
 5365                        languages,
 5366                        language,
 5367                        cx,
 5368                    );
 5369
 5370                    let query = if filter_completions { query } else { None };
 5371                    let matches_task = if let Some(query) = query {
 5372                        menu.do_async_filtering(query, cx)
 5373                    } else {
 5374                        Task::ready(menu.unfiltered_matches())
 5375                    };
 5376                    (menu, matches_task)
 5377                }) else {
 5378                    return;
 5379                };
 5380
 5381                let matches = matches_task.await;
 5382
 5383                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5384                    // Newer menu already set, so exit.
 5385                    match editor.context_menu.borrow().as_ref() {
 5386                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5387                            if prev_menu.id > id {
 5388                                return;
 5389                            }
 5390                        }
 5391                        _ => {}
 5392                    };
 5393
 5394                    // Only valid to take prev_menu because it the new menu is immediately set
 5395                    // below, or the menu is hidden.
 5396                    match editor.context_menu.borrow_mut().take() {
 5397                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5398                            let position_matches =
 5399                                if prev_menu.initial_position == menu.initial_position {
 5400                                    true
 5401                                } else {
 5402                                    let snapshot = editor.buffer.read(cx).read(cx);
 5403                                    prev_menu.initial_position.to_offset(&snapshot)
 5404                                        == menu.initial_position.to_offset(&snapshot)
 5405                                };
 5406                            if position_matches {
 5407                                // Preserve markdown cache before `set_filter_results` because it will
 5408                                // try to populate the documentation cache.
 5409                                menu.preserve_markdown_cache(prev_menu);
 5410                            }
 5411                        }
 5412                        _ => {}
 5413                    };
 5414
 5415                    menu.set_filter_results(matches, provider, window, cx);
 5416                }) else {
 5417                    return;
 5418                };
 5419
 5420                menu.visible().then_some(menu)
 5421            };
 5422
 5423            editor
 5424                .update_in(cx, |editor, window, cx| {
 5425                    if editor.focus_handle.is_focused(window) {
 5426                        if let Some(menu) = menu {
 5427                            *editor.context_menu.borrow_mut() =
 5428                                Some(CodeContextMenu::Completions(menu));
 5429
 5430                            crate::hover_popover::hide_hover(editor, cx);
 5431                            if editor.show_edit_predictions_in_menu() {
 5432                                editor.update_visible_inline_completion(window, cx);
 5433                            } else {
 5434                                editor.discard_inline_completion(false, cx);
 5435                            }
 5436
 5437                            cx.notify();
 5438                            return;
 5439                        }
 5440                    }
 5441
 5442                    if editor.completion_tasks.len() <= 1 {
 5443                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5444                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5445                        // If it was already hidden and we don't show inline completions in the menu, we should
 5446                        // also show the inline-completion when available.
 5447                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5448                            editor.update_visible_inline_completion(window, cx);
 5449                        }
 5450                    }
 5451                })
 5452                .ok();
 5453        });
 5454
 5455        self.completion_tasks.push((id, task));
 5456    }
 5457
 5458    #[cfg(feature = "test-support")]
 5459    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5460        let menu = self.context_menu.borrow();
 5461        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5462            let completions = menu.completions.borrow();
 5463            Some(completions.to_vec())
 5464        } else {
 5465            None
 5466        }
 5467    }
 5468
 5469    pub fn with_completions_menu_matching_id<R>(
 5470        &self,
 5471        id: CompletionId,
 5472        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5473    ) -> R {
 5474        let mut context_menu = self.context_menu.borrow_mut();
 5475        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5476            return f(None);
 5477        };
 5478        if completions_menu.id != id {
 5479            return f(None);
 5480        }
 5481        f(Some(completions_menu))
 5482    }
 5483
 5484    pub fn confirm_completion(
 5485        &mut self,
 5486        action: &ConfirmCompletion,
 5487        window: &mut Window,
 5488        cx: &mut Context<Self>,
 5489    ) -> Option<Task<Result<()>>> {
 5490        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5491        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5492    }
 5493
 5494    pub fn confirm_completion_insert(
 5495        &mut self,
 5496        _: &ConfirmCompletionInsert,
 5497        window: &mut Window,
 5498        cx: &mut Context<Self>,
 5499    ) -> Option<Task<Result<()>>> {
 5500        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5501        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5502    }
 5503
 5504    pub fn confirm_completion_replace(
 5505        &mut self,
 5506        _: &ConfirmCompletionReplace,
 5507        window: &mut Window,
 5508        cx: &mut Context<Self>,
 5509    ) -> Option<Task<Result<()>>> {
 5510        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5511        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5512    }
 5513
 5514    pub fn compose_completion(
 5515        &mut self,
 5516        action: &ComposeCompletion,
 5517        window: &mut Window,
 5518        cx: &mut Context<Self>,
 5519    ) -> Option<Task<Result<()>>> {
 5520        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5521        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5522    }
 5523
 5524    fn do_completion(
 5525        &mut self,
 5526        item_ix: Option<usize>,
 5527        intent: CompletionIntent,
 5528        window: &mut Window,
 5529        cx: &mut Context<Editor>,
 5530    ) -> Option<Task<Result<()>>> {
 5531        use language::ToOffset as _;
 5532
 5533        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5534        else {
 5535            return None;
 5536        };
 5537
 5538        let candidate_id = {
 5539            let entries = completions_menu.entries.borrow();
 5540            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5541            if self.show_edit_predictions_in_menu() {
 5542                self.discard_inline_completion(true, cx);
 5543            }
 5544            mat.candidate_id
 5545        };
 5546
 5547        let completion = completions_menu
 5548            .completions
 5549            .borrow()
 5550            .get(candidate_id)?
 5551            .clone();
 5552        cx.stop_propagation();
 5553
 5554        let buffer_handle = completions_menu.buffer.clone();
 5555
 5556        let CompletionEdit {
 5557            new_text,
 5558            snippet,
 5559            replace_range,
 5560        } = process_completion_for_edit(
 5561            &completion,
 5562            intent,
 5563            &buffer_handle,
 5564            &completions_menu.initial_position.text_anchor,
 5565            cx,
 5566        );
 5567
 5568        let buffer = buffer_handle.read(cx);
 5569        let snapshot = self.buffer.read(cx).snapshot(cx);
 5570        let newest_anchor = self.selections.newest_anchor();
 5571        let replace_range_multibuffer = {
 5572            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5573            let multibuffer_anchor = snapshot
 5574                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5575                .unwrap()
 5576                ..snapshot
 5577                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5578                    .unwrap();
 5579            multibuffer_anchor.start.to_offset(&snapshot)
 5580                ..multibuffer_anchor.end.to_offset(&snapshot)
 5581        };
 5582        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5583            return None;
 5584        }
 5585
 5586        let old_text = buffer
 5587            .text_for_range(replace_range.clone())
 5588            .collect::<String>();
 5589        let lookbehind = newest_anchor
 5590            .start
 5591            .text_anchor
 5592            .to_offset(buffer)
 5593            .saturating_sub(replace_range.start);
 5594        let lookahead = replace_range
 5595            .end
 5596            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5597        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5598        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5599
 5600        let selections = self.selections.all::<usize>(cx);
 5601        let mut ranges = Vec::new();
 5602        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5603
 5604        for selection in &selections {
 5605            let range = if selection.id == newest_anchor.id {
 5606                replace_range_multibuffer.clone()
 5607            } else {
 5608                let mut range = selection.range();
 5609
 5610                // if prefix is present, don't duplicate it
 5611                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5612                    range.start = range.start.saturating_sub(lookbehind);
 5613
 5614                    // if suffix is also present, mimic the newest cursor and replace it
 5615                    if selection.id != newest_anchor.id
 5616                        && snapshot.contains_str_at(range.end, suffix)
 5617                    {
 5618                        range.end += lookahead;
 5619                    }
 5620                }
 5621                range
 5622            };
 5623
 5624            ranges.push(range.clone());
 5625
 5626            if !self.linked_edit_ranges.is_empty() {
 5627                let start_anchor = snapshot.anchor_before(range.start);
 5628                let end_anchor = snapshot.anchor_after(range.end);
 5629                if let Some(ranges) = self
 5630                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5631                {
 5632                    for (buffer, edits) in ranges {
 5633                        linked_edits
 5634                            .entry(buffer.clone())
 5635                            .or_default()
 5636                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5637                    }
 5638                }
 5639            }
 5640        }
 5641
 5642        let common_prefix_len = old_text
 5643            .chars()
 5644            .zip(new_text.chars())
 5645            .take_while(|(a, b)| a == b)
 5646            .map(|(a, _)| a.len_utf8())
 5647            .sum::<usize>();
 5648
 5649        cx.emit(EditorEvent::InputHandled {
 5650            utf16_range_to_replace: None,
 5651            text: new_text[common_prefix_len..].into(),
 5652        });
 5653
 5654        self.transact(window, cx, |this, window, cx| {
 5655            if let Some(mut snippet) = snippet {
 5656                snippet.text = new_text.to_string();
 5657                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5658            } else {
 5659                this.buffer.update(cx, |buffer, cx| {
 5660                    let auto_indent = match completion.insert_text_mode {
 5661                        Some(InsertTextMode::AS_IS) => None,
 5662                        _ => this.autoindent_mode.clone(),
 5663                    };
 5664                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5665                    buffer.edit(edits, auto_indent, cx);
 5666                });
 5667            }
 5668            for (buffer, edits) in linked_edits {
 5669                buffer.update(cx, |buffer, cx| {
 5670                    let snapshot = buffer.snapshot();
 5671                    let edits = edits
 5672                        .into_iter()
 5673                        .map(|(range, text)| {
 5674                            use text::ToPoint as TP;
 5675                            let end_point = TP::to_point(&range.end, &snapshot);
 5676                            let start_point = TP::to_point(&range.start, &snapshot);
 5677                            (start_point..end_point, text)
 5678                        })
 5679                        .sorted_by_key(|(range, _)| range.start);
 5680                    buffer.edit(edits, None, cx);
 5681                })
 5682            }
 5683
 5684            this.refresh_inline_completion(true, false, window, cx);
 5685        });
 5686
 5687        let show_new_completions_on_confirm = completion
 5688            .confirm
 5689            .as_ref()
 5690            .map_or(false, |confirm| confirm(intent, window, cx));
 5691        if show_new_completions_on_confirm {
 5692            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5693        }
 5694
 5695        let provider = self.completion_provider.as_ref()?;
 5696        drop(completion);
 5697        let apply_edits = provider.apply_additional_edits_for_completion(
 5698            buffer_handle,
 5699            completions_menu.completions.clone(),
 5700            candidate_id,
 5701            true,
 5702            cx,
 5703        );
 5704
 5705        let editor_settings = EditorSettings::get_global(cx);
 5706        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5707            // After the code completion is finished, users often want to know what signatures are needed.
 5708            // so we should automatically call signature_help
 5709            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5710        }
 5711
 5712        Some(cx.foreground_executor().spawn(async move {
 5713            apply_edits.await?;
 5714            Ok(())
 5715        }))
 5716    }
 5717
 5718    pub fn toggle_code_actions(
 5719        &mut self,
 5720        action: &ToggleCodeActions,
 5721        window: &mut Window,
 5722        cx: &mut Context<Self>,
 5723    ) {
 5724        let quick_launch = action.quick_launch;
 5725        let mut context_menu = self.context_menu.borrow_mut();
 5726        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5727            if code_actions.deployed_from == action.deployed_from {
 5728                // Toggle if we're selecting the same one
 5729                *context_menu = None;
 5730                cx.notify();
 5731                return;
 5732            } else {
 5733                // Otherwise, clear it and start a new one
 5734                *context_menu = None;
 5735                cx.notify();
 5736            }
 5737        }
 5738        drop(context_menu);
 5739        let snapshot = self.snapshot(window, cx);
 5740        let deployed_from = action.deployed_from.clone();
 5741        let action = action.clone();
 5742        self.completion_tasks.clear();
 5743        self.discard_inline_completion(false, cx);
 5744
 5745        let multibuffer_point = match &action.deployed_from {
 5746            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5747                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5748            }
 5749            _ => self.selections.newest::<Point>(cx).head(),
 5750        };
 5751        let Some((buffer, buffer_row)) = snapshot
 5752            .buffer_snapshot
 5753            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5754            .and_then(|(buffer_snapshot, range)| {
 5755                self.buffer()
 5756                    .read(cx)
 5757                    .buffer(buffer_snapshot.remote_id())
 5758                    .map(|buffer| (buffer, range.start.row))
 5759            })
 5760        else {
 5761            return;
 5762        };
 5763        let buffer_id = buffer.read(cx).remote_id();
 5764        let tasks = self
 5765            .tasks
 5766            .get(&(buffer_id, buffer_row))
 5767            .map(|t| Arc::new(t.to_owned()));
 5768
 5769        if !self.focus_handle.is_focused(window) {
 5770            return;
 5771        }
 5772        let project = self.project.clone();
 5773
 5774        let code_actions_task = match deployed_from {
 5775            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5776            _ => self.code_actions(buffer_row, window, cx),
 5777        };
 5778
 5779        let runnable_task = match deployed_from {
 5780            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5781            _ => {
 5782                let mut task_context_task = Task::ready(None);
 5783                if let Some(tasks) = &tasks {
 5784                    if let Some(project) = project {
 5785                        task_context_task =
 5786                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5787                    }
 5788                }
 5789
 5790                cx.spawn_in(window, {
 5791                    let buffer = buffer.clone();
 5792                    async move |editor, cx| {
 5793                        let task_context = task_context_task.await;
 5794
 5795                        let resolved_tasks =
 5796                            tasks
 5797                                .zip(task_context.clone())
 5798                                .map(|(tasks, task_context)| ResolvedTasks {
 5799                                    templates: tasks.resolve(&task_context).collect(),
 5800                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5801                                        multibuffer_point.row,
 5802                                        tasks.column,
 5803                                    )),
 5804                                });
 5805                        let debug_scenarios = editor
 5806                            .update(cx, |editor, cx| {
 5807                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5808                            })?
 5809                            .await;
 5810                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5811                    }
 5812                })
 5813            }
 5814        };
 5815
 5816        cx.spawn_in(window, async move |editor, cx| {
 5817            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5818            let code_actions = code_actions_task.await;
 5819            let spawn_straight_away = quick_launch
 5820                && resolved_tasks
 5821                    .as_ref()
 5822                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5823                && code_actions
 5824                    .as_ref()
 5825                    .map_or(true, |actions| actions.is_empty())
 5826                && debug_scenarios.is_empty();
 5827
 5828            editor.update_in(cx, |editor, window, cx| {
 5829                crate::hover_popover::hide_hover(editor, cx);
 5830                *editor.context_menu.borrow_mut() =
 5831                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5832                        buffer,
 5833                        actions: CodeActionContents::new(
 5834                            resolved_tasks,
 5835                            code_actions,
 5836                            debug_scenarios,
 5837                            task_context.unwrap_or_default(),
 5838                        ),
 5839                        selected_item: Default::default(),
 5840                        scroll_handle: UniformListScrollHandle::default(),
 5841                        deployed_from,
 5842                    }));
 5843                if spawn_straight_away {
 5844                    if let Some(task) = editor.confirm_code_action(
 5845                        &ConfirmCodeAction { item_ix: Some(0) },
 5846                        window,
 5847                        cx,
 5848                    ) {
 5849                        cx.notify();
 5850                        return task;
 5851                    }
 5852                }
 5853
 5854                Task::ready(Ok(()))
 5855            })
 5856        })
 5857        .detach_and_log_err(cx);
 5858    }
 5859
 5860    fn debug_scenarios(
 5861        &mut self,
 5862        resolved_tasks: &Option<ResolvedTasks>,
 5863        buffer: &Entity<Buffer>,
 5864        cx: &mut App,
 5865    ) -> Task<Vec<task::DebugScenario>> {
 5866        if cx.has_flag::<DebuggerFeatureFlag>() {
 5867            maybe!({
 5868                let project = self.project.as_ref()?;
 5869                let dap_store = project.read(cx).dap_store();
 5870                let mut scenarios = vec![];
 5871                let resolved_tasks = resolved_tasks.as_ref()?;
 5872                let buffer = buffer.read(cx);
 5873                let language = buffer.language()?;
 5874                let file = buffer.file();
 5875                let debug_adapter = language_settings(language.name().into(), file, cx)
 5876                    .debuggers
 5877                    .first()
 5878                    .map(SharedString::from)
 5879                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5880
 5881                dap_store.update(cx, |dap_store, cx| {
 5882                    for (_, task) in &resolved_tasks.templates {
 5883                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5884                            task.original_task().clone(),
 5885                            debug_adapter.clone().into(),
 5886                            task.display_label().to_owned().into(),
 5887                            cx,
 5888                        );
 5889                        scenarios.push(maybe_scenario);
 5890                    }
 5891                });
 5892                Some(cx.background_spawn(async move {
 5893                    let scenarios = futures::future::join_all(scenarios)
 5894                        .await
 5895                        .into_iter()
 5896                        .flatten()
 5897                        .collect::<Vec<_>>();
 5898                    scenarios
 5899                }))
 5900            })
 5901            .unwrap_or_else(|| Task::ready(vec![]))
 5902        } else {
 5903            Task::ready(vec![])
 5904        }
 5905    }
 5906
 5907    fn code_actions(
 5908        &mut self,
 5909        buffer_row: u32,
 5910        window: &mut Window,
 5911        cx: &mut Context<Self>,
 5912    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5913        let mut task = self.code_actions_task.take();
 5914        cx.spawn_in(window, async move |editor, cx| {
 5915            while let Some(prev_task) = task {
 5916                prev_task.await.log_err();
 5917                task = editor
 5918                    .update(cx, |this, _| this.code_actions_task.take())
 5919                    .ok()?;
 5920            }
 5921
 5922            editor
 5923                .update(cx, |editor, cx| {
 5924                    editor
 5925                        .available_code_actions
 5926                        .clone()
 5927                        .and_then(|(location, code_actions)| {
 5928                            let snapshot = location.buffer.read(cx).snapshot();
 5929                            let point_range = location.range.to_point(&snapshot);
 5930                            let point_range = point_range.start.row..=point_range.end.row;
 5931                            if point_range.contains(&buffer_row) {
 5932                                Some(code_actions)
 5933                            } else {
 5934                                None
 5935                            }
 5936                        })
 5937                })
 5938                .ok()
 5939                .flatten()
 5940        })
 5941    }
 5942
 5943    pub fn confirm_code_action(
 5944        &mut self,
 5945        action: &ConfirmCodeAction,
 5946        window: &mut Window,
 5947        cx: &mut Context<Self>,
 5948    ) -> Option<Task<Result<()>>> {
 5949        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5950
 5951        let actions_menu =
 5952            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5953                menu
 5954            } else {
 5955                return None;
 5956            };
 5957
 5958        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5959        let action = actions_menu.actions.get(action_ix)?;
 5960        let title = action.label();
 5961        let buffer = actions_menu.buffer;
 5962        let workspace = self.workspace()?;
 5963
 5964        match action {
 5965            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5966                workspace.update(cx, |workspace, cx| {
 5967                    workspace.schedule_resolved_task(
 5968                        task_source_kind,
 5969                        resolved_task,
 5970                        false,
 5971                        window,
 5972                        cx,
 5973                    );
 5974
 5975                    Some(Task::ready(Ok(())))
 5976                })
 5977            }
 5978            CodeActionsItem::CodeAction {
 5979                excerpt_id,
 5980                action,
 5981                provider,
 5982            } => {
 5983                let apply_code_action =
 5984                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5985                let workspace = workspace.downgrade();
 5986                Some(cx.spawn_in(window, async move |editor, cx| {
 5987                    let project_transaction = apply_code_action.await?;
 5988                    Self::open_project_transaction(
 5989                        &editor,
 5990                        workspace,
 5991                        project_transaction,
 5992                        title,
 5993                        cx,
 5994                    )
 5995                    .await
 5996                }))
 5997            }
 5998            CodeActionsItem::DebugScenario(scenario) => {
 5999                let context = actions_menu.actions.context.clone();
 6000
 6001                workspace.update(cx, |workspace, cx| {
 6002                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6003                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6004                });
 6005                Some(Task::ready(Ok(())))
 6006            }
 6007        }
 6008    }
 6009
 6010    pub async fn open_project_transaction(
 6011        this: &WeakEntity<Editor>,
 6012        workspace: WeakEntity<Workspace>,
 6013        transaction: ProjectTransaction,
 6014        title: String,
 6015        cx: &mut AsyncWindowContext,
 6016    ) -> Result<()> {
 6017        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6018        cx.update(|_, cx| {
 6019            entries.sort_unstable_by_key(|(buffer, _)| {
 6020                buffer.read(cx).file().map(|f| f.path().clone())
 6021            });
 6022        })?;
 6023
 6024        // If the project transaction's edits are all contained within this editor, then
 6025        // avoid opening a new editor to display them.
 6026
 6027        if let Some((buffer, transaction)) = entries.first() {
 6028            if entries.len() == 1 {
 6029                let excerpt = this.update(cx, |editor, cx| {
 6030                    editor
 6031                        .buffer()
 6032                        .read(cx)
 6033                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6034                })?;
 6035                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6036                    if excerpted_buffer == *buffer {
 6037                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6038                            let excerpt_range = excerpt_range.to_offset(buffer);
 6039                            buffer
 6040                                .edited_ranges_for_transaction::<usize>(transaction)
 6041                                .all(|range| {
 6042                                    excerpt_range.start <= range.start
 6043                                        && excerpt_range.end >= range.end
 6044                                })
 6045                        })?;
 6046
 6047                        if all_edits_within_excerpt {
 6048                            return Ok(());
 6049                        }
 6050                    }
 6051                }
 6052            }
 6053        } else {
 6054            return Ok(());
 6055        }
 6056
 6057        let mut ranges_to_highlight = Vec::new();
 6058        let excerpt_buffer = cx.new(|cx| {
 6059            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6060            for (buffer_handle, transaction) in &entries {
 6061                let edited_ranges = buffer_handle
 6062                    .read(cx)
 6063                    .edited_ranges_for_transaction::<Point>(transaction)
 6064                    .collect::<Vec<_>>();
 6065                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6066                    PathKey::for_buffer(buffer_handle, cx),
 6067                    buffer_handle.clone(),
 6068                    edited_ranges,
 6069                    DEFAULT_MULTIBUFFER_CONTEXT,
 6070                    cx,
 6071                );
 6072
 6073                ranges_to_highlight.extend(ranges);
 6074            }
 6075            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6076            multibuffer
 6077        })?;
 6078
 6079        workspace.update_in(cx, |workspace, window, cx| {
 6080            let project = workspace.project().clone();
 6081            let editor =
 6082                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6083            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6084            editor.update(cx, |editor, cx| {
 6085                editor.highlight_background::<Self>(
 6086                    &ranges_to_highlight,
 6087                    |theme| theme.editor_highlighted_line_background,
 6088                    cx,
 6089                );
 6090            });
 6091        })?;
 6092
 6093        Ok(())
 6094    }
 6095
 6096    pub fn clear_code_action_providers(&mut self) {
 6097        self.code_action_providers.clear();
 6098        self.available_code_actions.take();
 6099    }
 6100
 6101    pub fn add_code_action_provider(
 6102        &mut self,
 6103        provider: Rc<dyn CodeActionProvider>,
 6104        window: &mut Window,
 6105        cx: &mut Context<Self>,
 6106    ) {
 6107        if self
 6108            .code_action_providers
 6109            .iter()
 6110            .any(|existing_provider| existing_provider.id() == provider.id())
 6111        {
 6112            return;
 6113        }
 6114
 6115        self.code_action_providers.push(provider);
 6116        self.refresh_code_actions(window, cx);
 6117    }
 6118
 6119    pub fn remove_code_action_provider(
 6120        &mut self,
 6121        id: Arc<str>,
 6122        window: &mut Window,
 6123        cx: &mut Context<Self>,
 6124    ) {
 6125        self.code_action_providers
 6126            .retain(|provider| provider.id() != id);
 6127        self.refresh_code_actions(window, cx);
 6128    }
 6129
 6130    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6131        !self.code_action_providers.is_empty()
 6132            && EditorSettings::get_global(cx).toolbar.code_actions
 6133    }
 6134
 6135    pub fn has_available_code_actions(&self) -> bool {
 6136        self.available_code_actions
 6137            .as_ref()
 6138            .is_some_and(|(_, actions)| !actions.is_empty())
 6139    }
 6140
 6141    fn render_inline_code_actions(
 6142        &self,
 6143        icon_size: ui::IconSize,
 6144        display_row: DisplayRow,
 6145        is_active: bool,
 6146        cx: &mut Context<Self>,
 6147    ) -> AnyElement {
 6148        let show_tooltip = !self.context_menu_visible();
 6149        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6150            .icon_size(icon_size)
 6151            .shape(ui::IconButtonShape::Square)
 6152            .style(ButtonStyle::Transparent)
 6153            .icon_color(ui::Color::Hidden)
 6154            .toggle_state(is_active)
 6155            .when(show_tooltip, |this| {
 6156                this.tooltip({
 6157                    let focus_handle = self.focus_handle.clone();
 6158                    move |window, cx| {
 6159                        Tooltip::for_action_in(
 6160                            "Toggle Code Actions",
 6161                            &ToggleCodeActions {
 6162                                deployed_from: None,
 6163                                quick_launch: false,
 6164                            },
 6165                            &focus_handle,
 6166                            window,
 6167                            cx,
 6168                        )
 6169                    }
 6170                })
 6171            })
 6172            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6173                window.focus(&editor.focus_handle(cx));
 6174                editor.toggle_code_actions(
 6175                    &crate::actions::ToggleCodeActions {
 6176                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6177                            display_row,
 6178                        )),
 6179                        quick_launch: false,
 6180                    },
 6181                    window,
 6182                    cx,
 6183                );
 6184            }))
 6185            .into_any_element()
 6186    }
 6187
 6188    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6189        &self.context_menu
 6190    }
 6191
 6192    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6193        let newest_selection = self.selections.newest_anchor().clone();
 6194        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6195        let buffer = self.buffer.read(cx);
 6196        if newest_selection.head().diff_base_anchor.is_some() {
 6197            return None;
 6198        }
 6199        let (start_buffer, start) =
 6200            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6201        let (end_buffer, end) =
 6202            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6203        if start_buffer != end_buffer {
 6204            return None;
 6205        }
 6206
 6207        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6208            cx.background_executor()
 6209                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6210                .await;
 6211
 6212            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6213                let providers = this.code_action_providers.clone();
 6214                let tasks = this
 6215                    .code_action_providers
 6216                    .iter()
 6217                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6218                    .collect::<Vec<_>>();
 6219                (providers, tasks)
 6220            })?;
 6221
 6222            let mut actions = Vec::new();
 6223            for (provider, provider_actions) in
 6224                providers.into_iter().zip(future::join_all(tasks).await)
 6225            {
 6226                if let Some(provider_actions) = provider_actions.log_err() {
 6227                    actions.extend(provider_actions.into_iter().map(|action| {
 6228                        AvailableCodeAction {
 6229                            excerpt_id: newest_selection.start.excerpt_id,
 6230                            action,
 6231                            provider: provider.clone(),
 6232                        }
 6233                    }));
 6234                }
 6235            }
 6236
 6237            this.update(cx, |this, cx| {
 6238                this.available_code_actions = if actions.is_empty() {
 6239                    None
 6240                } else {
 6241                    Some((
 6242                        Location {
 6243                            buffer: start_buffer,
 6244                            range: start..end,
 6245                        },
 6246                        actions.into(),
 6247                    ))
 6248                };
 6249                cx.notify();
 6250            })
 6251        }));
 6252        None
 6253    }
 6254
 6255    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6256        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6257            self.show_git_blame_inline = false;
 6258
 6259            self.show_git_blame_inline_delay_task =
 6260                Some(cx.spawn_in(window, async move |this, cx| {
 6261                    cx.background_executor().timer(delay).await;
 6262
 6263                    this.update(cx, |this, cx| {
 6264                        this.show_git_blame_inline = true;
 6265                        cx.notify();
 6266                    })
 6267                    .log_err();
 6268                }));
 6269        }
 6270    }
 6271
 6272    fn show_blame_popover(
 6273        &mut self,
 6274        blame_entry: &BlameEntry,
 6275        position: gpui::Point<Pixels>,
 6276        cx: &mut Context<Self>,
 6277    ) {
 6278        if let Some(state) = &mut self.inline_blame_popover {
 6279            state.hide_task.take();
 6280        } else {
 6281            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6282            let blame_entry = blame_entry.clone();
 6283            let show_task = cx.spawn(async move |editor, cx| {
 6284                cx.background_executor()
 6285                    .timer(std::time::Duration::from_millis(delay))
 6286                    .await;
 6287                editor
 6288                    .update(cx, |editor, cx| {
 6289                        editor.inline_blame_popover_show_task.take();
 6290                        let Some(blame) = editor.blame.as_ref() else {
 6291                            return;
 6292                        };
 6293                        let blame = blame.read(cx);
 6294                        let details = blame.details_for_entry(&blame_entry);
 6295                        let markdown = cx.new(|cx| {
 6296                            Markdown::new(
 6297                                details
 6298                                    .as_ref()
 6299                                    .map(|message| message.message.clone())
 6300                                    .unwrap_or_default(),
 6301                                None,
 6302                                None,
 6303                                cx,
 6304                            )
 6305                        });
 6306                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6307                            position,
 6308                            hide_task: None,
 6309                            popover_bounds: None,
 6310                            popover_state: InlineBlamePopoverState {
 6311                                scroll_handle: ScrollHandle::new(),
 6312                                commit_message: details,
 6313                                markdown,
 6314                            },
 6315                        });
 6316                        cx.notify();
 6317                    })
 6318                    .ok();
 6319            });
 6320            self.inline_blame_popover_show_task = Some(show_task);
 6321        }
 6322    }
 6323
 6324    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6325        self.inline_blame_popover_show_task.take();
 6326        if let Some(state) = &mut self.inline_blame_popover {
 6327            let hide_task = cx.spawn(async move |editor, cx| {
 6328                cx.background_executor()
 6329                    .timer(std::time::Duration::from_millis(100))
 6330                    .await;
 6331                editor
 6332                    .update(cx, |editor, cx| {
 6333                        editor.inline_blame_popover.take();
 6334                        cx.notify();
 6335                    })
 6336                    .ok();
 6337            });
 6338            state.hide_task = Some(hide_task);
 6339        }
 6340    }
 6341
 6342    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6343        if self.pending_rename.is_some() {
 6344            return None;
 6345        }
 6346
 6347        let provider = self.semantics_provider.clone()?;
 6348        let buffer = self.buffer.read(cx);
 6349        let newest_selection = self.selections.newest_anchor().clone();
 6350        let cursor_position = newest_selection.head();
 6351        let (cursor_buffer, cursor_buffer_position) =
 6352            buffer.text_anchor_for_position(cursor_position, cx)?;
 6353        let (tail_buffer, tail_buffer_position) =
 6354            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6355        if cursor_buffer != tail_buffer {
 6356            return None;
 6357        }
 6358
 6359        let snapshot = cursor_buffer.read(cx).snapshot();
 6360        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6361        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6362        if start_word_range != end_word_range {
 6363            self.document_highlights_task.take();
 6364            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6365            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6366            return None;
 6367        }
 6368
 6369        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6370        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6371            cx.background_executor()
 6372                .timer(Duration::from_millis(debounce))
 6373                .await;
 6374
 6375            let highlights = if let Some(highlights) = cx
 6376                .update(|cx| {
 6377                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6378                })
 6379                .ok()
 6380                .flatten()
 6381            {
 6382                highlights.await.log_err()
 6383            } else {
 6384                None
 6385            };
 6386
 6387            if let Some(highlights) = highlights {
 6388                this.update(cx, |this, cx| {
 6389                    if this.pending_rename.is_some() {
 6390                        return;
 6391                    }
 6392
 6393                    let buffer_id = cursor_position.buffer_id;
 6394                    let buffer = this.buffer.read(cx);
 6395                    if !buffer
 6396                        .text_anchor_for_position(cursor_position, cx)
 6397                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6398                    {
 6399                        return;
 6400                    }
 6401
 6402                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6403                    let mut write_ranges = Vec::new();
 6404                    let mut read_ranges = Vec::new();
 6405                    for highlight in highlights {
 6406                        for (excerpt_id, excerpt_range) in
 6407                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6408                        {
 6409                            let start = highlight
 6410                                .range
 6411                                .start
 6412                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6413                            let end = highlight
 6414                                .range
 6415                                .end
 6416                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6417                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6418                                continue;
 6419                            }
 6420
 6421                            let range = Anchor {
 6422                                buffer_id,
 6423                                excerpt_id,
 6424                                text_anchor: start,
 6425                                diff_base_anchor: None,
 6426                            }..Anchor {
 6427                                buffer_id,
 6428                                excerpt_id,
 6429                                text_anchor: end,
 6430                                diff_base_anchor: None,
 6431                            };
 6432                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6433                                write_ranges.push(range);
 6434                            } else {
 6435                                read_ranges.push(range);
 6436                            }
 6437                        }
 6438                    }
 6439
 6440                    this.highlight_background::<DocumentHighlightRead>(
 6441                        &read_ranges,
 6442                        |theme| theme.editor_document_highlight_read_background,
 6443                        cx,
 6444                    );
 6445                    this.highlight_background::<DocumentHighlightWrite>(
 6446                        &write_ranges,
 6447                        |theme| theme.editor_document_highlight_write_background,
 6448                        cx,
 6449                    );
 6450                    cx.notify();
 6451                })
 6452                .log_err();
 6453            }
 6454        }));
 6455        None
 6456    }
 6457
 6458    fn prepare_highlight_query_from_selection(
 6459        &mut self,
 6460        cx: &mut Context<Editor>,
 6461    ) -> Option<(String, Range<Anchor>)> {
 6462        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6463            return None;
 6464        }
 6465        if !EditorSettings::get_global(cx).selection_highlight {
 6466            return None;
 6467        }
 6468        if self.selections.count() != 1 || self.selections.line_mode {
 6469            return None;
 6470        }
 6471        let selection = self.selections.newest::<Point>(cx);
 6472        if selection.is_empty() || selection.start.row != selection.end.row {
 6473            return None;
 6474        }
 6475        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6476        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6477        let query = multi_buffer_snapshot
 6478            .text_for_range(selection_anchor_range.clone())
 6479            .collect::<String>();
 6480        if query.trim().is_empty() {
 6481            return None;
 6482        }
 6483        Some((query, selection_anchor_range))
 6484    }
 6485
 6486    fn update_selection_occurrence_highlights(
 6487        &mut self,
 6488        query_text: String,
 6489        query_range: Range<Anchor>,
 6490        multi_buffer_range_to_query: Range<Point>,
 6491        use_debounce: bool,
 6492        window: &mut Window,
 6493        cx: &mut Context<Editor>,
 6494    ) -> Task<()> {
 6495        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6496        cx.spawn_in(window, async move |editor, cx| {
 6497            if use_debounce {
 6498                cx.background_executor()
 6499                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6500                    .await;
 6501            }
 6502            let match_task = cx.background_spawn(async move {
 6503                let buffer_ranges = multi_buffer_snapshot
 6504                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6505                    .into_iter()
 6506                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6507                let mut match_ranges = Vec::new();
 6508                let Ok(regex) = project::search::SearchQuery::text(
 6509                    query_text.clone(),
 6510                    false,
 6511                    false,
 6512                    false,
 6513                    Default::default(),
 6514                    Default::default(),
 6515                    false,
 6516                    None,
 6517                ) else {
 6518                    return Vec::default();
 6519                };
 6520                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6521                    match_ranges.extend(
 6522                        regex
 6523                            .search(&buffer_snapshot, Some(search_range.clone()))
 6524                            .await
 6525                            .into_iter()
 6526                            .filter_map(|match_range| {
 6527                                let match_start = buffer_snapshot
 6528                                    .anchor_after(search_range.start + match_range.start);
 6529                                let match_end = buffer_snapshot
 6530                                    .anchor_before(search_range.start + match_range.end);
 6531                                let match_anchor_range = Anchor::range_in_buffer(
 6532                                    excerpt_id,
 6533                                    buffer_snapshot.remote_id(),
 6534                                    match_start..match_end,
 6535                                );
 6536                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6537                            }),
 6538                    );
 6539                }
 6540                match_ranges
 6541            });
 6542            let match_ranges = match_task.await;
 6543            editor
 6544                .update_in(cx, |editor, _, cx| {
 6545                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6546                    if !match_ranges.is_empty() {
 6547                        editor.highlight_background::<SelectedTextHighlight>(
 6548                            &match_ranges,
 6549                            |theme| theme.editor_document_highlight_bracket_background,
 6550                            cx,
 6551                        )
 6552                    }
 6553                })
 6554                .log_err();
 6555        })
 6556    }
 6557
 6558    fn refresh_selected_text_highlights(
 6559        &mut self,
 6560        on_buffer_edit: bool,
 6561        window: &mut Window,
 6562        cx: &mut Context<Editor>,
 6563    ) {
 6564        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6565        else {
 6566            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6567            self.quick_selection_highlight_task.take();
 6568            self.debounced_selection_highlight_task.take();
 6569            return;
 6570        };
 6571        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6572        if on_buffer_edit
 6573            || self
 6574                .quick_selection_highlight_task
 6575                .as_ref()
 6576                .map_or(true, |(prev_anchor_range, _)| {
 6577                    prev_anchor_range != &query_range
 6578                })
 6579        {
 6580            let multi_buffer_visible_start = self
 6581                .scroll_manager
 6582                .anchor()
 6583                .anchor
 6584                .to_point(&multi_buffer_snapshot);
 6585            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6586                multi_buffer_visible_start
 6587                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6588                Bias::Left,
 6589            );
 6590            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6591            self.quick_selection_highlight_task = Some((
 6592                query_range.clone(),
 6593                self.update_selection_occurrence_highlights(
 6594                    query_text.clone(),
 6595                    query_range.clone(),
 6596                    multi_buffer_visible_range,
 6597                    false,
 6598                    window,
 6599                    cx,
 6600                ),
 6601            ));
 6602        }
 6603        if on_buffer_edit
 6604            || self
 6605                .debounced_selection_highlight_task
 6606                .as_ref()
 6607                .map_or(true, |(prev_anchor_range, _)| {
 6608                    prev_anchor_range != &query_range
 6609                })
 6610        {
 6611            let multi_buffer_start = multi_buffer_snapshot
 6612                .anchor_before(0)
 6613                .to_point(&multi_buffer_snapshot);
 6614            let multi_buffer_end = multi_buffer_snapshot
 6615                .anchor_after(multi_buffer_snapshot.len())
 6616                .to_point(&multi_buffer_snapshot);
 6617            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6618            self.debounced_selection_highlight_task = Some((
 6619                query_range.clone(),
 6620                self.update_selection_occurrence_highlights(
 6621                    query_text,
 6622                    query_range,
 6623                    multi_buffer_full_range,
 6624                    true,
 6625                    window,
 6626                    cx,
 6627                ),
 6628            ));
 6629        }
 6630    }
 6631
 6632    pub fn refresh_inline_completion(
 6633        &mut self,
 6634        debounce: bool,
 6635        user_requested: bool,
 6636        window: &mut Window,
 6637        cx: &mut Context<Self>,
 6638    ) -> Option<()> {
 6639        let provider = self.edit_prediction_provider()?;
 6640        let cursor = self.selections.newest_anchor().head();
 6641        let (buffer, cursor_buffer_position) =
 6642            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6643
 6644        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6645            self.discard_inline_completion(false, cx);
 6646            return None;
 6647        }
 6648
 6649        if !user_requested
 6650            && (!self.should_show_edit_predictions()
 6651                || !self.is_focused(window)
 6652                || buffer.read(cx).is_empty())
 6653        {
 6654            self.discard_inline_completion(false, cx);
 6655            return None;
 6656        }
 6657
 6658        self.update_visible_inline_completion(window, cx);
 6659        provider.refresh(
 6660            self.project.clone(),
 6661            buffer,
 6662            cursor_buffer_position,
 6663            debounce,
 6664            cx,
 6665        );
 6666        Some(())
 6667    }
 6668
 6669    fn show_edit_predictions_in_menu(&self) -> bool {
 6670        match self.edit_prediction_settings {
 6671            EditPredictionSettings::Disabled => false,
 6672            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6673        }
 6674    }
 6675
 6676    pub fn edit_predictions_enabled(&self) -> bool {
 6677        match self.edit_prediction_settings {
 6678            EditPredictionSettings::Disabled => false,
 6679            EditPredictionSettings::Enabled { .. } => true,
 6680        }
 6681    }
 6682
 6683    fn edit_prediction_requires_modifier(&self) -> bool {
 6684        match self.edit_prediction_settings {
 6685            EditPredictionSettings::Disabled => false,
 6686            EditPredictionSettings::Enabled {
 6687                preview_requires_modifier,
 6688                ..
 6689            } => preview_requires_modifier,
 6690        }
 6691    }
 6692
 6693    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6694        if self.edit_prediction_provider.is_none() {
 6695            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6696        } else {
 6697            let selection = self.selections.newest_anchor();
 6698            let cursor = selection.head();
 6699
 6700            if let Some((buffer, cursor_buffer_position)) =
 6701                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6702            {
 6703                self.edit_prediction_settings =
 6704                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6705            }
 6706        }
 6707    }
 6708
 6709    fn edit_prediction_settings_at_position(
 6710        &self,
 6711        buffer: &Entity<Buffer>,
 6712        buffer_position: language::Anchor,
 6713        cx: &App,
 6714    ) -> EditPredictionSettings {
 6715        if !self.mode.is_full()
 6716            || !self.show_inline_completions_override.unwrap_or(true)
 6717            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6718        {
 6719            return EditPredictionSettings::Disabled;
 6720        }
 6721
 6722        let buffer = buffer.read(cx);
 6723
 6724        let file = buffer.file();
 6725
 6726        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6727            return EditPredictionSettings::Disabled;
 6728        };
 6729
 6730        let by_provider = matches!(
 6731            self.menu_inline_completions_policy,
 6732            MenuInlineCompletionsPolicy::ByProvider
 6733        );
 6734
 6735        let show_in_menu = by_provider
 6736            && self
 6737                .edit_prediction_provider
 6738                .as_ref()
 6739                .map_or(false, |provider| {
 6740                    provider.provider.show_completions_in_menu()
 6741                });
 6742
 6743        let preview_requires_modifier =
 6744            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6745
 6746        EditPredictionSettings::Enabled {
 6747            show_in_menu,
 6748            preview_requires_modifier,
 6749        }
 6750    }
 6751
 6752    fn should_show_edit_predictions(&self) -> bool {
 6753        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6754    }
 6755
 6756    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6757        matches!(
 6758            self.edit_prediction_preview,
 6759            EditPredictionPreview::Active { .. }
 6760        )
 6761    }
 6762
 6763    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6764        let cursor = self.selections.newest_anchor().head();
 6765        if let Some((buffer, cursor_position)) =
 6766            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6767        {
 6768            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6769        } else {
 6770            false
 6771        }
 6772    }
 6773
 6774    pub fn supports_minimap(&self, cx: &App) -> bool {
 6775        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6776    }
 6777
 6778    fn edit_predictions_enabled_in_buffer(
 6779        &self,
 6780        buffer: &Entity<Buffer>,
 6781        buffer_position: language::Anchor,
 6782        cx: &App,
 6783    ) -> bool {
 6784        maybe!({
 6785            if self.read_only(cx) {
 6786                return Some(false);
 6787            }
 6788            let provider = self.edit_prediction_provider()?;
 6789            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6790                return Some(false);
 6791            }
 6792            let buffer = buffer.read(cx);
 6793            let Some(file) = buffer.file() else {
 6794                return Some(true);
 6795            };
 6796            let settings = all_language_settings(Some(file), cx);
 6797            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6798        })
 6799        .unwrap_or(false)
 6800    }
 6801
 6802    fn cycle_inline_completion(
 6803        &mut self,
 6804        direction: Direction,
 6805        window: &mut Window,
 6806        cx: &mut Context<Self>,
 6807    ) -> Option<()> {
 6808        let provider = self.edit_prediction_provider()?;
 6809        let cursor = self.selections.newest_anchor().head();
 6810        let (buffer, cursor_buffer_position) =
 6811            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6812        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6813            return None;
 6814        }
 6815
 6816        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6817        self.update_visible_inline_completion(window, cx);
 6818
 6819        Some(())
 6820    }
 6821
 6822    pub fn show_inline_completion(
 6823        &mut self,
 6824        _: &ShowEditPrediction,
 6825        window: &mut Window,
 6826        cx: &mut Context<Self>,
 6827    ) {
 6828        if !self.has_active_inline_completion() {
 6829            self.refresh_inline_completion(false, true, window, cx);
 6830            return;
 6831        }
 6832
 6833        self.update_visible_inline_completion(window, cx);
 6834    }
 6835
 6836    pub fn display_cursor_names(
 6837        &mut self,
 6838        _: &DisplayCursorNames,
 6839        window: &mut Window,
 6840        cx: &mut Context<Self>,
 6841    ) {
 6842        self.show_cursor_names(window, cx);
 6843    }
 6844
 6845    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6846        self.show_cursor_names = true;
 6847        cx.notify();
 6848        cx.spawn_in(window, async move |this, cx| {
 6849            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6850            this.update(cx, |this, cx| {
 6851                this.show_cursor_names = false;
 6852                cx.notify()
 6853            })
 6854            .ok()
 6855        })
 6856        .detach();
 6857    }
 6858
 6859    pub fn next_edit_prediction(
 6860        &mut self,
 6861        _: &NextEditPrediction,
 6862        window: &mut Window,
 6863        cx: &mut Context<Self>,
 6864    ) {
 6865        if self.has_active_inline_completion() {
 6866            self.cycle_inline_completion(Direction::Next, window, cx);
 6867        } else {
 6868            let is_copilot_disabled = self
 6869                .refresh_inline_completion(false, true, window, cx)
 6870                .is_none();
 6871            if is_copilot_disabled {
 6872                cx.propagate();
 6873            }
 6874        }
 6875    }
 6876
 6877    pub fn previous_edit_prediction(
 6878        &mut self,
 6879        _: &PreviousEditPrediction,
 6880        window: &mut Window,
 6881        cx: &mut Context<Self>,
 6882    ) {
 6883        if self.has_active_inline_completion() {
 6884            self.cycle_inline_completion(Direction::Prev, window, cx);
 6885        } else {
 6886            let is_copilot_disabled = self
 6887                .refresh_inline_completion(false, true, window, cx)
 6888                .is_none();
 6889            if is_copilot_disabled {
 6890                cx.propagate();
 6891            }
 6892        }
 6893    }
 6894
 6895    pub fn accept_edit_prediction(
 6896        &mut self,
 6897        _: &AcceptEditPrediction,
 6898        window: &mut Window,
 6899        cx: &mut Context<Self>,
 6900    ) {
 6901        if self.show_edit_predictions_in_menu() {
 6902            self.hide_context_menu(window, cx);
 6903        }
 6904
 6905        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6906            return;
 6907        };
 6908
 6909        self.report_inline_completion_event(
 6910            active_inline_completion.completion_id.clone(),
 6911            true,
 6912            cx,
 6913        );
 6914
 6915        match &active_inline_completion.completion {
 6916            InlineCompletion::Move { target, .. } => {
 6917                let target = *target;
 6918
 6919                if let Some(position_map) = &self.last_position_map {
 6920                    if position_map
 6921                        .visible_row_range
 6922                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6923                        || !self.edit_prediction_requires_modifier()
 6924                    {
 6925                        self.unfold_ranges(&[target..target], true, false, cx);
 6926                        // Note that this is also done in vim's handler of the Tab action.
 6927                        self.change_selections(
 6928                            Some(Autoscroll::newest()),
 6929                            window,
 6930                            cx,
 6931                            |selections| {
 6932                                selections.select_anchor_ranges([target..target]);
 6933                            },
 6934                        );
 6935                        self.clear_row_highlights::<EditPredictionPreview>();
 6936
 6937                        self.edit_prediction_preview
 6938                            .set_previous_scroll_position(None);
 6939                    } else {
 6940                        self.edit_prediction_preview
 6941                            .set_previous_scroll_position(Some(
 6942                                position_map.snapshot.scroll_anchor,
 6943                            ));
 6944
 6945                        self.highlight_rows::<EditPredictionPreview>(
 6946                            target..target,
 6947                            cx.theme().colors().editor_highlighted_line_background,
 6948                            RowHighlightOptions {
 6949                                autoscroll: true,
 6950                                ..Default::default()
 6951                            },
 6952                            cx,
 6953                        );
 6954                        self.request_autoscroll(Autoscroll::fit(), cx);
 6955                    }
 6956                }
 6957            }
 6958            InlineCompletion::Edit { edits, .. } => {
 6959                if let Some(provider) = self.edit_prediction_provider() {
 6960                    provider.accept(cx);
 6961                }
 6962
 6963                // Store the transaction ID and selections before applying the edit
 6964                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6965
 6966                let snapshot = self.buffer.read(cx).snapshot(cx);
 6967                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6968
 6969                self.buffer.update(cx, |buffer, cx| {
 6970                    buffer.edit(edits.iter().cloned(), None, cx)
 6971                });
 6972
 6973                self.change_selections(None, window, cx, |s| {
 6974                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6975                });
 6976
 6977                let selections = self.selections.disjoint_anchors();
 6978                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6979                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6980                    if has_new_transaction {
 6981                        self.selection_history
 6982                            .insert_transaction(transaction_id_now, selections);
 6983                    }
 6984                }
 6985
 6986                self.update_visible_inline_completion(window, cx);
 6987                if self.active_inline_completion.is_none() {
 6988                    self.refresh_inline_completion(true, true, window, cx);
 6989                }
 6990
 6991                cx.notify();
 6992            }
 6993        }
 6994
 6995        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6996    }
 6997
 6998    pub fn accept_partial_inline_completion(
 6999        &mut self,
 7000        _: &AcceptPartialEditPrediction,
 7001        window: &mut Window,
 7002        cx: &mut Context<Self>,
 7003    ) {
 7004        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7005            return;
 7006        };
 7007        if self.selections.count() != 1 {
 7008            return;
 7009        }
 7010
 7011        self.report_inline_completion_event(
 7012            active_inline_completion.completion_id.clone(),
 7013            true,
 7014            cx,
 7015        );
 7016
 7017        match &active_inline_completion.completion {
 7018            InlineCompletion::Move { target, .. } => {
 7019                let target = *target;
 7020                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7021                    selections.select_anchor_ranges([target..target]);
 7022                });
 7023            }
 7024            InlineCompletion::Edit { edits, .. } => {
 7025                // Find an insertion that starts at the cursor position.
 7026                let snapshot = self.buffer.read(cx).snapshot(cx);
 7027                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7028                let insertion = edits.iter().find_map(|(range, text)| {
 7029                    let range = range.to_offset(&snapshot);
 7030                    if range.is_empty() && range.start == cursor_offset {
 7031                        Some(text)
 7032                    } else {
 7033                        None
 7034                    }
 7035                });
 7036
 7037                if let Some(text) = insertion {
 7038                    let mut partial_completion = text
 7039                        .chars()
 7040                        .by_ref()
 7041                        .take_while(|c| c.is_alphabetic())
 7042                        .collect::<String>();
 7043                    if partial_completion.is_empty() {
 7044                        partial_completion = text
 7045                            .chars()
 7046                            .by_ref()
 7047                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7048                            .collect::<String>();
 7049                    }
 7050
 7051                    cx.emit(EditorEvent::InputHandled {
 7052                        utf16_range_to_replace: None,
 7053                        text: partial_completion.clone().into(),
 7054                    });
 7055
 7056                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7057
 7058                    self.refresh_inline_completion(true, true, window, cx);
 7059                    cx.notify();
 7060                } else {
 7061                    self.accept_edit_prediction(&Default::default(), window, cx);
 7062                }
 7063            }
 7064        }
 7065    }
 7066
 7067    fn discard_inline_completion(
 7068        &mut self,
 7069        should_report_inline_completion_event: bool,
 7070        cx: &mut Context<Self>,
 7071    ) -> bool {
 7072        if should_report_inline_completion_event {
 7073            let completion_id = self
 7074                .active_inline_completion
 7075                .as_ref()
 7076                .and_then(|active_completion| active_completion.completion_id.clone());
 7077
 7078            self.report_inline_completion_event(completion_id, false, cx);
 7079        }
 7080
 7081        if let Some(provider) = self.edit_prediction_provider() {
 7082            provider.discard(cx);
 7083        }
 7084
 7085        self.take_active_inline_completion(cx)
 7086    }
 7087
 7088    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7089        let Some(provider) = self.edit_prediction_provider() else {
 7090            return;
 7091        };
 7092
 7093        let Some((_, buffer, _)) = self
 7094            .buffer
 7095            .read(cx)
 7096            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7097        else {
 7098            return;
 7099        };
 7100
 7101        let extension = buffer
 7102            .read(cx)
 7103            .file()
 7104            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7105
 7106        let event_type = match accepted {
 7107            true => "Edit Prediction Accepted",
 7108            false => "Edit Prediction Discarded",
 7109        };
 7110        telemetry::event!(
 7111            event_type,
 7112            provider = provider.name(),
 7113            prediction_id = id,
 7114            suggestion_accepted = accepted,
 7115            file_extension = extension,
 7116        );
 7117    }
 7118
 7119    pub fn has_active_inline_completion(&self) -> bool {
 7120        self.active_inline_completion.is_some()
 7121    }
 7122
 7123    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7124        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7125            return false;
 7126        };
 7127
 7128        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7129        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7130        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7131        true
 7132    }
 7133
 7134    /// Returns true when we're displaying the edit prediction popover below the cursor
 7135    /// like we are not previewing and the LSP autocomplete menu is visible
 7136    /// or we are in `when_holding_modifier` mode.
 7137    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7138        if self.edit_prediction_preview_is_active()
 7139            || !self.show_edit_predictions_in_menu()
 7140            || !self.edit_predictions_enabled()
 7141        {
 7142            return false;
 7143        }
 7144
 7145        if self.has_visible_completions_menu() {
 7146            return true;
 7147        }
 7148
 7149        has_completion && self.edit_prediction_requires_modifier()
 7150    }
 7151
 7152    fn handle_modifiers_changed(
 7153        &mut self,
 7154        modifiers: Modifiers,
 7155        position_map: &PositionMap,
 7156        window: &mut Window,
 7157        cx: &mut Context<Self>,
 7158    ) {
 7159        if self.show_edit_predictions_in_menu() {
 7160            self.update_edit_prediction_preview(&modifiers, window, cx);
 7161        }
 7162
 7163        self.update_selection_mode(&modifiers, position_map, window, cx);
 7164
 7165        let mouse_position = window.mouse_position();
 7166        if !position_map.text_hitbox.is_hovered(window) {
 7167            return;
 7168        }
 7169
 7170        self.update_hovered_link(
 7171            position_map.point_for_position(mouse_position),
 7172            &position_map.snapshot,
 7173            modifiers,
 7174            window,
 7175            cx,
 7176        )
 7177    }
 7178
 7179    fn multi_cursor_modifier(
 7180        cursor_event: bool,
 7181        modifiers: &Modifiers,
 7182        cx: &mut Context<Self>,
 7183    ) -> bool {
 7184        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7185        if cursor_event {
 7186            match multi_cursor_setting {
 7187                MultiCursorModifier::Alt => modifiers.alt,
 7188                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7189            }
 7190        } else {
 7191            match multi_cursor_setting {
 7192                MultiCursorModifier::Alt => modifiers.secondary(),
 7193                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7194            }
 7195        }
 7196    }
 7197
 7198    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7199        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7200    }
 7201
 7202    fn update_selection_mode(
 7203        &mut self,
 7204        modifiers: &Modifiers,
 7205        position_map: &PositionMap,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7210        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7211            || self.selections.pending.is_none()
 7212        {
 7213            return;
 7214        }
 7215
 7216        let mouse_position = window.mouse_position();
 7217        let point_for_position = position_map.point_for_position(mouse_position);
 7218        let position = point_for_position.previous_valid;
 7219
 7220        self.select(
 7221            SelectPhase::BeginColumnar {
 7222                position,
 7223                reset: false,
 7224                goal_column: point_for_position.exact_unclipped.column(),
 7225            },
 7226            window,
 7227            cx,
 7228        );
 7229    }
 7230
 7231    fn update_edit_prediction_preview(
 7232        &mut self,
 7233        modifiers: &Modifiers,
 7234        window: &mut Window,
 7235        cx: &mut Context<Self>,
 7236    ) {
 7237        let mut modifiers_held = false;
 7238        if let Some(accept_keystroke) = self
 7239            .accept_edit_prediction_keybind(false, window, cx)
 7240            .keystroke()
 7241        {
 7242            modifiers_held = modifiers_held
 7243                || (&accept_keystroke.modifiers == modifiers
 7244                    && accept_keystroke.modifiers.modified());
 7245        };
 7246        if let Some(accept_partial_keystroke) = self
 7247            .accept_edit_prediction_keybind(true, window, cx)
 7248            .keystroke()
 7249        {
 7250            modifiers_held = modifiers_held
 7251                || (&accept_partial_keystroke.modifiers == modifiers
 7252                    && accept_partial_keystroke.modifiers.modified());
 7253        }
 7254
 7255        if modifiers_held {
 7256            if matches!(
 7257                self.edit_prediction_preview,
 7258                EditPredictionPreview::Inactive { .. }
 7259            ) {
 7260                self.edit_prediction_preview = EditPredictionPreview::Active {
 7261                    previous_scroll_position: None,
 7262                    since: Instant::now(),
 7263                };
 7264
 7265                self.update_visible_inline_completion(window, cx);
 7266                cx.notify();
 7267            }
 7268        } else if let EditPredictionPreview::Active {
 7269            previous_scroll_position,
 7270            since,
 7271        } = self.edit_prediction_preview
 7272        {
 7273            if let (Some(previous_scroll_position), Some(position_map)) =
 7274                (previous_scroll_position, self.last_position_map.as_ref())
 7275            {
 7276                self.set_scroll_position(
 7277                    previous_scroll_position
 7278                        .scroll_position(&position_map.snapshot.display_snapshot),
 7279                    window,
 7280                    cx,
 7281                );
 7282            }
 7283
 7284            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7285                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7286            };
 7287            self.clear_row_highlights::<EditPredictionPreview>();
 7288            self.update_visible_inline_completion(window, cx);
 7289            cx.notify();
 7290        }
 7291    }
 7292
 7293    fn update_visible_inline_completion(
 7294        &mut self,
 7295        _window: &mut Window,
 7296        cx: &mut Context<Self>,
 7297    ) -> Option<()> {
 7298        let selection = self.selections.newest_anchor();
 7299        let cursor = selection.head();
 7300        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7301        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7302        let excerpt_id = cursor.excerpt_id;
 7303
 7304        let show_in_menu = self.show_edit_predictions_in_menu();
 7305        let completions_menu_has_precedence = !show_in_menu
 7306            && (self.context_menu.borrow().is_some()
 7307                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7308
 7309        if completions_menu_has_precedence
 7310            || !offset_selection.is_empty()
 7311            || self
 7312                .active_inline_completion
 7313                .as_ref()
 7314                .map_or(false, |completion| {
 7315                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7316                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7317                    !invalidation_range.contains(&offset_selection.head())
 7318                })
 7319        {
 7320            self.discard_inline_completion(false, cx);
 7321            return None;
 7322        }
 7323
 7324        self.take_active_inline_completion(cx);
 7325        let Some(provider) = self.edit_prediction_provider() else {
 7326            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7327            return None;
 7328        };
 7329
 7330        let (buffer, cursor_buffer_position) =
 7331            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7332
 7333        self.edit_prediction_settings =
 7334            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7335
 7336        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7337
 7338        if self.edit_prediction_indent_conflict {
 7339            let cursor_point = cursor.to_point(&multibuffer);
 7340
 7341            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7342
 7343            if let Some((_, indent)) = indents.iter().next() {
 7344                if indent.len == cursor_point.column {
 7345                    self.edit_prediction_indent_conflict = false;
 7346                }
 7347            }
 7348        }
 7349
 7350        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7351        let edits = inline_completion
 7352            .edits
 7353            .into_iter()
 7354            .flat_map(|(range, new_text)| {
 7355                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7356                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7357                Some((start..end, new_text))
 7358            })
 7359            .collect::<Vec<_>>();
 7360        if edits.is_empty() {
 7361            return None;
 7362        }
 7363
 7364        let first_edit_start = edits.first().unwrap().0.start;
 7365        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7366        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7367
 7368        let last_edit_end = edits.last().unwrap().0.end;
 7369        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7370        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7371
 7372        let cursor_row = cursor.to_point(&multibuffer).row;
 7373
 7374        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7375
 7376        let mut inlay_ids = Vec::new();
 7377        let invalidation_row_range;
 7378        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7379            Some(cursor_row..edit_end_row)
 7380        } else if cursor_row > edit_end_row {
 7381            Some(edit_start_row..cursor_row)
 7382        } else {
 7383            None
 7384        };
 7385        let is_move =
 7386            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7387        let completion = if is_move {
 7388            invalidation_row_range =
 7389                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7390            let target = first_edit_start;
 7391            InlineCompletion::Move { target, snapshot }
 7392        } else {
 7393            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7394                && !self.inline_completions_hidden_for_vim_mode;
 7395
 7396            if show_completions_in_buffer {
 7397                if edits
 7398                    .iter()
 7399                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7400                {
 7401                    let mut inlays = Vec::new();
 7402                    for (range, new_text) in &edits {
 7403                        let inlay = Inlay::inline_completion(
 7404                            post_inc(&mut self.next_inlay_id),
 7405                            range.start,
 7406                            new_text.as_str(),
 7407                        );
 7408                        inlay_ids.push(inlay.id);
 7409                        inlays.push(inlay);
 7410                    }
 7411
 7412                    self.splice_inlays(&[], inlays, cx);
 7413                } else {
 7414                    let background_color = cx.theme().status().deleted_background;
 7415                    self.highlight_text::<InlineCompletionHighlight>(
 7416                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7417                        HighlightStyle {
 7418                            background_color: Some(background_color),
 7419                            ..Default::default()
 7420                        },
 7421                        cx,
 7422                    );
 7423                }
 7424            }
 7425
 7426            invalidation_row_range = edit_start_row..edit_end_row;
 7427
 7428            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7429                if provider.show_tab_accept_marker() {
 7430                    EditDisplayMode::TabAccept
 7431                } else {
 7432                    EditDisplayMode::Inline
 7433                }
 7434            } else {
 7435                EditDisplayMode::DiffPopover
 7436            };
 7437
 7438            InlineCompletion::Edit {
 7439                edits,
 7440                edit_preview: inline_completion.edit_preview,
 7441                display_mode,
 7442                snapshot,
 7443            }
 7444        };
 7445
 7446        let invalidation_range = multibuffer
 7447            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7448            ..multibuffer.anchor_after(Point::new(
 7449                invalidation_row_range.end,
 7450                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7451            ));
 7452
 7453        self.stale_inline_completion_in_menu = None;
 7454        self.active_inline_completion = Some(InlineCompletionState {
 7455            inlay_ids,
 7456            completion,
 7457            completion_id: inline_completion.id,
 7458            invalidation_range,
 7459        });
 7460
 7461        cx.notify();
 7462
 7463        Some(())
 7464    }
 7465
 7466    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7467        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7468    }
 7469
 7470    fn clear_tasks(&mut self) {
 7471        self.tasks.clear()
 7472    }
 7473
 7474    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7475        if self.tasks.insert(key, value).is_some() {
 7476            // This case should hopefully be rare, but just in case...
 7477            log::error!(
 7478                "multiple different run targets found on a single line, only the last target will be rendered"
 7479            )
 7480        }
 7481    }
 7482
 7483    /// Get all display points of breakpoints that will be rendered within editor
 7484    ///
 7485    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7486    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7487    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7488    fn active_breakpoints(
 7489        &self,
 7490        range: Range<DisplayRow>,
 7491        window: &mut Window,
 7492        cx: &mut Context<Self>,
 7493    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7494        let mut breakpoint_display_points = HashMap::default();
 7495
 7496        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7497            return breakpoint_display_points;
 7498        };
 7499
 7500        let snapshot = self.snapshot(window, cx);
 7501
 7502        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7503        let Some(project) = self.project.as_ref() else {
 7504            return breakpoint_display_points;
 7505        };
 7506
 7507        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7508            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7509
 7510        for (buffer_snapshot, range, excerpt_id) in
 7511            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7512        {
 7513            let Some(buffer) = project
 7514                .read(cx)
 7515                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7516            else {
 7517                continue;
 7518            };
 7519            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7520                &buffer,
 7521                Some(
 7522                    buffer_snapshot.anchor_before(range.start)
 7523                        ..buffer_snapshot.anchor_after(range.end),
 7524                ),
 7525                buffer_snapshot,
 7526                cx,
 7527            );
 7528            for (breakpoint, state) in breakpoints {
 7529                let multi_buffer_anchor =
 7530                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7531                let position = multi_buffer_anchor
 7532                    .to_point(&multi_buffer_snapshot)
 7533                    .to_display_point(&snapshot);
 7534
 7535                breakpoint_display_points.insert(
 7536                    position.row(),
 7537                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7538                );
 7539            }
 7540        }
 7541
 7542        breakpoint_display_points
 7543    }
 7544
 7545    fn breakpoint_context_menu(
 7546        &self,
 7547        anchor: Anchor,
 7548        window: &mut Window,
 7549        cx: &mut Context<Self>,
 7550    ) -> Entity<ui::ContextMenu> {
 7551        let weak_editor = cx.weak_entity();
 7552        let focus_handle = self.focus_handle(cx);
 7553
 7554        let row = self
 7555            .buffer
 7556            .read(cx)
 7557            .snapshot(cx)
 7558            .summary_for_anchor::<Point>(&anchor)
 7559            .row;
 7560
 7561        let breakpoint = self
 7562            .breakpoint_at_row(row, window, cx)
 7563            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7564
 7565        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7566            "Edit Log Breakpoint"
 7567        } else {
 7568            "Set Log Breakpoint"
 7569        };
 7570
 7571        let condition_breakpoint_msg = if breakpoint
 7572            .as_ref()
 7573            .is_some_and(|bp| bp.1.condition.is_some())
 7574        {
 7575            "Edit Condition Breakpoint"
 7576        } else {
 7577            "Set Condition Breakpoint"
 7578        };
 7579
 7580        let hit_condition_breakpoint_msg = if breakpoint
 7581            .as_ref()
 7582            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7583        {
 7584            "Edit Hit Condition Breakpoint"
 7585        } else {
 7586            "Set Hit Condition Breakpoint"
 7587        };
 7588
 7589        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7590            "Unset Breakpoint"
 7591        } else {
 7592            "Set Breakpoint"
 7593        };
 7594
 7595        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7596
 7597        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7598            BreakpointState::Enabled => Some("Disable"),
 7599            BreakpointState::Disabled => Some("Enable"),
 7600        });
 7601
 7602        let (anchor, breakpoint) =
 7603            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7604
 7605        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7606            menu.on_blur_subscription(Subscription::new(|| {}))
 7607                .context(focus_handle)
 7608                .when(run_to_cursor, |this| {
 7609                    let weak_editor = weak_editor.clone();
 7610                    this.entry("Run to cursor", None, move |window, cx| {
 7611                        weak_editor
 7612                            .update(cx, |editor, cx| {
 7613                                editor.change_selections(None, window, cx, |s| {
 7614                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7615                                });
 7616                            })
 7617                            .ok();
 7618
 7619                        window.dispatch_action(Box::new(RunToCursor), cx);
 7620                    })
 7621                    .separator()
 7622                })
 7623                .when_some(toggle_state_msg, |this, msg| {
 7624                    this.entry(msg, None, {
 7625                        let weak_editor = weak_editor.clone();
 7626                        let breakpoint = breakpoint.clone();
 7627                        move |_window, cx| {
 7628                            weak_editor
 7629                                .update(cx, |this, cx| {
 7630                                    this.edit_breakpoint_at_anchor(
 7631                                        anchor,
 7632                                        breakpoint.as_ref().clone(),
 7633                                        BreakpointEditAction::InvertState,
 7634                                        cx,
 7635                                    );
 7636                                })
 7637                                .log_err();
 7638                        }
 7639                    })
 7640                })
 7641                .entry(set_breakpoint_msg, None, {
 7642                    let weak_editor = weak_editor.clone();
 7643                    let breakpoint = breakpoint.clone();
 7644                    move |_window, cx| {
 7645                        weak_editor
 7646                            .update(cx, |this, cx| {
 7647                                this.edit_breakpoint_at_anchor(
 7648                                    anchor,
 7649                                    breakpoint.as_ref().clone(),
 7650                                    BreakpointEditAction::Toggle,
 7651                                    cx,
 7652                                );
 7653                            })
 7654                            .log_err();
 7655                    }
 7656                })
 7657                .entry(log_breakpoint_msg, None, {
 7658                    let breakpoint = breakpoint.clone();
 7659                    let weak_editor = weak_editor.clone();
 7660                    move |window, cx| {
 7661                        weak_editor
 7662                            .update(cx, |this, cx| {
 7663                                this.add_edit_breakpoint_block(
 7664                                    anchor,
 7665                                    breakpoint.as_ref(),
 7666                                    BreakpointPromptEditAction::Log,
 7667                                    window,
 7668                                    cx,
 7669                                );
 7670                            })
 7671                            .log_err();
 7672                    }
 7673                })
 7674                .entry(condition_breakpoint_msg, None, {
 7675                    let breakpoint = breakpoint.clone();
 7676                    let weak_editor = weak_editor.clone();
 7677                    move |window, cx| {
 7678                        weak_editor
 7679                            .update(cx, |this, cx| {
 7680                                this.add_edit_breakpoint_block(
 7681                                    anchor,
 7682                                    breakpoint.as_ref(),
 7683                                    BreakpointPromptEditAction::Condition,
 7684                                    window,
 7685                                    cx,
 7686                                );
 7687                            })
 7688                            .log_err();
 7689                    }
 7690                })
 7691                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7692                    weak_editor
 7693                        .update(cx, |this, cx| {
 7694                            this.add_edit_breakpoint_block(
 7695                                anchor,
 7696                                breakpoint.as_ref(),
 7697                                BreakpointPromptEditAction::HitCondition,
 7698                                window,
 7699                                cx,
 7700                            );
 7701                        })
 7702                        .log_err();
 7703                })
 7704        })
 7705    }
 7706
 7707    fn render_breakpoint(
 7708        &self,
 7709        position: Anchor,
 7710        row: DisplayRow,
 7711        breakpoint: &Breakpoint,
 7712        state: Option<BreakpointSessionState>,
 7713        cx: &mut Context<Self>,
 7714    ) -> IconButton {
 7715        let is_rejected = state.is_some_and(|s| !s.verified);
 7716        // Is it a breakpoint that shows up when hovering over gutter?
 7717        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7718            (false, false),
 7719            |PhantomBreakpointIndicator {
 7720                 is_active,
 7721                 display_row,
 7722                 collides_with_existing_breakpoint,
 7723             }| {
 7724                (
 7725                    is_active && display_row == row,
 7726                    collides_with_existing_breakpoint,
 7727                )
 7728            },
 7729        );
 7730
 7731        let (color, icon) = {
 7732            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7733                (false, false) => ui::IconName::DebugBreakpoint,
 7734                (true, false) => ui::IconName::DebugLogBreakpoint,
 7735                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7736                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7737            };
 7738
 7739            let color = if is_phantom {
 7740                Color::Hint
 7741            } else if is_rejected {
 7742                Color::Disabled
 7743            } else {
 7744                Color::Debugger
 7745            };
 7746
 7747            (color, icon)
 7748        };
 7749
 7750        let breakpoint = Arc::from(breakpoint.clone());
 7751
 7752        let alt_as_text = gpui::Keystroke {
 7753            modifiers: Modifiers::secondary_key(),
 7754            ..Default::default()
 7755        };
 7756        let primary_action_text = if breakpoint.is_disabled() {
 7757            "Enable breakpoint"
 7758        } else if is_phantom && !collides_with_existing {
 7759            "Set breakpoint"
 7760        } else {
 7761            "Unset breakpoint"
 7762        };
 7763        let focus_handle = self.focus_handle.clone();
 7764
 7765        let meta = if is_rejected {
 7766            SharedString::from("No executable code is associated with this line.")
 7767        } else if collides_with_existing && !breakpoint.is_disabled() {
 7768            SharedString::from(format!(
 7769                "{alt_as_text}-click to disable,\nright-click for more options."
 7770            ))
 7771        } else {
 7772            SharedString::from("Right-click for more options.")
 7773        };
 7774        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7775            .icon_size(IconSize::XSmall)
 7776            .size(ui::ButtonSize::None)
 7777            .when(is_rejected, |this| {
 7778                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7779            })
 7780            .icon_color(color)
 7781            .style(ButtonStyle::Transparent)
 7782            .on_click(cx.listener({
 7783                let breakpoint = breakpoint.clone();
 7784
 7785                move |editor, event: &ClickEvent, window, cx| {
 7786                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7787                        BreakpointEditAction::InvertState
 7788                    } else {
 7789                        BreakpointEditAction::Toggle
 7790                    };
 7791
 7792                    window.focus(&editor.focus_handle(cx));
 7793                    editor.edit_breakpoint_at_anchor(
 7794                        position,
 7795                        breakpoint.as_ref().clone(),
 7796                        edit_action,
 7797                        cx,
 7798                    );
 7799                }
 7800            }))
 7801            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7802                editor.set_breakpoint_context_menu(
 7803                    row,
 7804                    Some(position),
 7805                    event.down.position,
 7806                    window,
 7807                    cx,
 7808                );
 7809            }))
 7810            .tooltip(move |window, cx| {
 7811                Tooltip::with_meta_in(
 7812                    primary_action_text,
 7813                    Some(&ToggleBreakpoint),
 7814                    meta.clone(),
 7815                    &focus_handle,
 7816                    window,
 7817                    cx,
 7818                )
 7819            })
 7820    }
 7821
 7822    fn build_tasks_context(
 7823        project: &Entity<Project>,
 7824        buffer: &Entity<Buffer>,
 7825        buffer_row: u32,
 7826        tasks: &Arc<RunnableTasks>,
 7827        cx: &mut Context<Self>,
 7828    ) -> Task<Option<task::TaskContext>> {
 7829        let position = Point::new(buffer_row, tasks.column);
 7830        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7831        let location = Location {
 7832            buffer: buffer.clone(),
 7833            range: range_start..range_start,
 7834        };
 7835        // Fill in the environmental variables from the tree-sitter captures
 7836        let mut captured_task_variables = TaskVariables::default();
 7837        for (capture_name, value) in tasks.extra_variables.clone() {
 7838            captured_task_variables.insert(
 7839                task::VariableName::Custom(capture_name.into()),
 7840                value.clone(),
 7841            );
 7842        }
 7843        project.update(cx, |project, cx| {
 7844            project.task_store().update(cx, |task_store, cx| {
 7845                task_store.task_context_for_location(captured_task_variables, location, cx)
 7846            })
 7847        })
 7848    }
 7849
 7850    pub fn spawn_nearest_task(
 7851        &mut self,
 7852        action: &SpawnNearestTask,
 7853        window: &mut Window,
 7854        cx: &mut Context<Self>,
 7855    ) {
 7856        let Some((workspace, _)) = self.workspace.clone() else {
 7857            return;
 7858        };
 7859        let Some(project) = self.project.clone() else {
 7860            return;
 7861        };
 7862
 7863        // Try to find a closest, enclosing node using tree-sitter that has a
 7864        // task
 7865        let Some((buffer, buffer_row, tasks)) = self
 7866            .find_enclosing_node_task(cx)
 7867            // Or find the task that's closest in row-distance.
 7868            .or_else(|| self.find_closest_task(cx))
 7869        else {
 7870            return;
 7871        };
 7872
 7873        let reveal_strategy = action.reveal;
 7874        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7875        cx.spawn_in(window, async move |_, cx| {
 7876            let context = task_context.await?;
 7877            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7878
 7879            let resolved = &mut resolved_task.resolved;
 7880            resolved.reveal = reveal_strategy;
 7881
 7882            workspace
 7883                .update_in(cx, |workspace, window, cx| {
 7884                    workspace.schedule_resolved_task(
 7885                        task_source_kind,
 7886                        resolved_task,
 7887                        false,
 7888                        window,
 7889                        cx,
 7890                    );
 7891                })
 7892                .ok()
 7893        })
 7894        .detach();
 7895    }
 7896
 7897    fn find_closest_task(
 7898        &mut self,
 7899        cx: &mut Context<Self>,
 7900    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7901        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7902
 7903        let ((buffer_id, row), tasks) = self
 7904            .tasks
 7905            .iter()
 7906            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7907
 7908        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7909        let tasks = Arc::new(tasks.to_owned());
 7910        Some((buffer, *row, tasks))
 7911    }
 7912
 7913    fn find_enclosing_node_task(
 7914        &mut self,
 7915        cx: &mut Context<Self>,
 7916    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7917        let snapshot = self.buffer.read(cx).snapshot(cx);
 7918        let offset = self.selections.newest::<usize>(cx).head();
 7919        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7920        let buffer_id = excerpt.buffer().remote_id();
 7921
 7922        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7923        let mut cursor = layer.node().walk();
 7924
 7925        while cursor.goto_first_child_for_byte(offset).is_some() {
 7926            if cursor.node().end_byte() == offset {
 7927                cursor.goto_next_sibling();
 7928            }
 7929        }
 7930
 7931        // Ascend to the smallest ancestor that contains the range and has a task.
 7932        loop {
 7933            let node = cursor.node();
 7934            let node_range = node.byte_range();
 7935            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7936
 7937            // Check if this node contains our offset
 7938            if node_range.start <= offset && node_range.end >= offset {
 7939                // If it contains offset, check for task
 7940                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7941                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7942                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7943                }
 7944            }
 7945
 7946            if !cursor.goto_parent() {
 7947                break;
 7948            }
 7949        }
 7950        None
 7951    }
 7952
 7953    fn render_run_indicator(
 7954        &self,
 7955        _style: &EditorStyle,
 7956        is_active: bool,
 7957        row: DisplayRow,
 7958        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7959        cx: &mut Context<Self>,
 7960    ) -> IconButton {
 7961        let color = Color::Muted;
 7962        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7963
 7964        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7965            .shape(ui::IconButtonShape::Square)
 7966            .icon_size(IconSize::XSmall)
 7967            .icon_color(color)
 7968            .toggle_state(is_active)
 7969            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7970                let quick_launch = e.down.button == MouseButton::Left;
 7971                window.focus(&editor.focus_handle(cx));
 7972                editor.toggle_code_actions(
 7973                    &ToggleCodeActions {
 7974                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7975                        quick_launch,
 7976                    },
 7977                    window,
 7978                    cx,
 7979                );
 7980            }))
 7981            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7982                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7983            }))
 7984    }
 7985
 7986    pub fn context_menu_visible(&self) -> bool {
 7987        !self.edit_prediction_preview_is_active()
 7988            && self
 7989                .context_menu
 7990                .borrow()
 7991                .as_ref()
 7992                .map_or(false, |menu| menu.visible())
 7993    }
 7994
 7995    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7996        self.context_menu
 7997            .borrow()
 7998            .as_ref()
 7999            .map(|menu| menu.origin())
 8000    }
 8001
 8002    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8003        self.context_menu_options = Some(options);
 8004    }
 8005
 8006    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8007    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8008
 8009    fn render_edit_prediction_popover(
 8010        &mut self,
 8011        text_bounds: &Bounds<Pixels>,
 8012        content_origin: gpui::Point<Pixels>,
 8013        right_margin: Pixels,
 8014        editor_snapshot: &EditorSnapshot,
 8015        visible_row_range: Range<DisplayRow>,
 8016        scroll_top: f32,
 8017        scroll_bottom: f32,
 8018        line_layouts: &[LineWithInvisibles],
 8019        line_height: Pixels,
 8020        scroll_pixel_position: gpui::Point<Pixels>,
 8021        newest_selection_head: Option<DisplayPoint>,
 8022        editor_width: Pixels,
 8023        style: &EditorStyle,
 8024        window: &mut Window,
 8025        cx: &mut App,
 8026    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8027        if self.mode().is_minimap() {
 8028            return None;
 8029        }
 8030        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8031
 8032        if self.edit_prediction_visible_in_cursor_popover(true) {
 8033            return None;
 8034        }
 8035
 8036        match &active_inline_completion.completion {
 8037            InlineCompletion::Move { target, .. } => {
 8038                let target_display_point = target.to_display_point(editor_snapshot);
 8039
 8040                if self.edit_prediction_requires_modifier() {
 8041                    if !self.edit_prediction_preview_is_active() {
 8042                        return None;
 8043                    }
 8044
 8045                    self.render_edit_prediction_modifier_jump_popover(
 8046                        text_bounds,
 8047                        content_origin,
 8048                        visible_row_range,
 8049                        line_layouts,
 8050                        line_height,
 8051                        scroll_pixel_position,
 8052                        newest_selection_head,
 8053                        target_display_point,
 8054                        window,
 8055                        cx,
 8056                    )
 8057                } else {
 8058                    self.render_edit_prediction_eager_jump_popover(
 8059                        text_bounds,
 8060                        content_origin,
 8061                        editor_snapshot,
 8062                        visible_row_range,
 8063                        scroll_top,
 8064                        scroll_bottom,
 8065                        line_height,
 8066                        scroll_pixel_position,
 8067                        target_display_point,
 8068                        editor_width,
 8069                        window,
 8070                        cx,
 8071                    )
 8072                }
 8073            }
 8074            InlineCompletion::Edit {
 8075                display_mode: EditDisplayMode::Inline,
 8076                ..
 8077            } => None,
 8078            InlineCompletion::Edit {
 8079                display_mode: EditDisplayMode::TabAccept,
 8080                edits,
 8081                ..
 8082            } => {
 8083                let range = &edits.first()?.0;
 8084                let target_display_point = range.end.to_display_point(editor_snapshot);
 8085
 8086                self.render_edit_prediction_end_of_line_popover(
 8087                    "Accept",
 8088                    editor_snapshot,
 8089                    visible_row_range,
 8090                    target_display_point,
 8091                    line_height,
 8092                    scroll_pixel_position,
 8093                    content_origin,
 8094                    editor_width,
 8095                    window,
 8096                    cx,
 8097                )
 8098            }
 8099            InlineCompletion::Edit {
 8100                edits,
 8101                edit_preview,
 8102                display_mode: EditDisplayMode::DiffPopover,
 8103                snapshot,
 8104            } => self.render_edit_prediction_diff_popover(
 8105                text_bounds,
 8106                content_origin,
 8107                right_margin,
 8108                editor_snapshot,
 8109                visible_row_range,
 8110                line_layouts,
 8111                line_height,
 8112                scroll_pixel_position,
 8113                newest_selection_head,
 8114                editor_width,
 8115                style,
 8116                edits,
 8117                edit_preview,
 8118                snapshot,
 8119                window,
 8120                cx,
 8121            ),
 8122        }
 8123    }
 8124
 8125    fn render_edit_prediction_modifier_jump_popover(
 8126        &mut self,
 8127        text_bounds: &Bounds<Pixels>,
 8128        content_origin: gpui::Point<Pixels>,
 8129        visible_row_range: Range<DisplayRow>,
 8130        line_layouts: &[LineWithInvisibles],
 8131        line_height: Pixels,
 8132        scroll_pixel_position: gpui::Point<Pixels>,
 8133        newest_selection_head: Option<DisplayPoint>,
 8134        target_display_point: DisplayPoint,
 8135        window: &mut Window,
 8136        cx: &mut App,
 8137    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8138        let scrolled_content_origin =
 8139            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8140
 8141        const SCROLL_PADDING_Y: Pixels = px(12.);
 8142
 8143        if target_display_point.row() < visible_row_range.start {
 8144            return self.render_edit_prediction_scroll_popover(
 8145                |_| SCROLL_PADDING_Y,
 8146                IconName::ArrowUp,
 8147                visible_row_range,
 8148                line_layouts,
 8149                newest_selection_head,
 8150                scrolled_content_origin,
 8151                window,
 8152                cx,
 8153            );
 8154        } else if target_display_point.row() >= visible_row_range.end {
 8155            return self.render_edit_prediction_scroll_popover(
 8156                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8157                IconName::ArrowDown,
 8158                visible_row_range,
 8159                line_layouts,
 8160                newest_selection_head,
 8161                scrolled_content_origin,
 8162                window,
 8163                cx,
 8164            );
 8165        }
 8166
 8167        const POLE_WIDTH: Pixels = px(2.);
 8168
 8169        let line_layout =
 8170            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8171        let target_column = target_display_point.column() as usize;
 8172
 8173        let target_x = line_layout.x_for_index(target_column);
 8174        let target_y =
 8175            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8176
 8177        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8178
 8179        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8180        border_color.l += 0.001;
 8181
 8182        let mut element = v_flex()
 8183            .items_end()
 8184            .when(flag_on_right, |el| el.items_start())
 8185            .child(if flag_on_right {
 8186                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8187                    .rounded_bl(px(0.))
 8188                    .rounded_tl(px(0.))
 8189                    .border_l_2()
 8190                    .border_color(border_color)
 8191            } else {
 8192                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8193                    .rounded_br(px(0.))
 8194                    .rounded_tr(px(0.))
 8195                    .border_r_2()
 8196                    .border_color(border_color)
 8197            })
 8198            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8199            .into_any();
 8200
 8201        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8202
 8203        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8204            - point(
 8205                if flag_on_right {
 8206                    POLE_WIDTH
 8207                } else {
 8208                    size.width - POLE_WIDTH
 8209                },
 8210                size.height - line_height,
 8211            );
 8212
 8213        origin.x = origin.x.max(content_origin.x);
 8214
 8215        element.prepaint_at(origin, window, cx);
 8216
 8217        Some((element, origin))
 8218    }
 8219
 8220    fn render_edit_prediction_scroll_popover(
 8221        &mut self,
 8222        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8223        scroll_icon: IconName,
 8224        visible_row_range: Range<DisplayRow>,
 8225        line_layouts: &[LineWithInvisibles],
 8226        newest_selection_head: Option<DisplayPoint>,
 8227        scrolled_content_origin: gpui::Point<Pixels>,
 8228        window: &mut Window,
 8229        cx: &mut App,
 8230    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8231        let mut element = self
 8232            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8233            .into_any();
 8234
 8235        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8236
 8237        let cursor = newest_selection_head?;
 8238        let cursor_row_layout =
 8239            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8240        let cursor_column = cursor.column() as usize;
 8241
 8242        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8243
 8244        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8245
 8246        element.prepaint_at(origin, window, cx);
 8247        Some((element, origin))
 8248    }
 8249
 8250    fn render_edit_prediction_eager_jump_popover(
 8251        &mut self,
 8252        text_bounds: &Bounds<Pixels>,
 8253        content_origin: gpui::Point<Pixels>,
 8254        editor_snapshot: &EditorSnapshot,
 8255        visible_row_range: Range<DisplayRow>,
 8256        scroll_top: f32,
 8257        scroll_bottom: f32,
 8258        line_height: Pixels,
 8259        scroll_pixel_position: gpui::Point<Pixels>,
 8260        target_display_point: DisplayPoint,
 8261        editor_width: Pixels,
 8262        window: &mut Window,
 8263        cx: &mut App,
 8264    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8265        if target_display_point.row().as_f32() < scroll_top {
 8266            let mut element = self
 8267                .render_edit_prediction_line_popover(
 8268                    "Jump to Edit",
 8269                    Some(IconName::ArrowUp),
 8270                    window,
 8271                    cx,
 8272                )?
 8273                .into_any();
 8274
 8275            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8276            let offset = point(
 8277                (text_bounds.size.width - size.width) / 2.,
 8278                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8279            );
 8280
 8281            let origin = text_bounds.origin + offset;
 8282            element.prepaint_at(origin, window, cx);
 8283            Some((element, origin))
 8284        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8285            let mut element = self
 8286                .render_edit_prediction_line_popover(
 8287                    "Jump to Edit",
 8288                    Some(IconName::ArrowDown),
 8289                    window,
 8290                    cx,
 8291                )?
 8292                .into_any();
 8293
 8294            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8295            let offset = point(
 8296                (text_bounds.size.width - size.width) / 2.,
 8297                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8298            );
 8299
 8300            let origin = text_bounds.origin + offset;
 8301            element.prepaint_at(origin, window, cx);
 8302            Some((element, origin))
 8303        } else {
 8304            self.render_edit_prediction_end_of_line_popover(
 8305                "Jump to Edit",
 8306                editor_snapshot,
 8307                visible_row_range,
 8308                target_display_point,
 8309                line_height,
 8310                scroll_pixel_position,
 8311                content_origin,
 8312                editor_width,
 8313                window,
 8314                cx,
 8315            )
 8316        }
 8317    }
 8318
 8319    fn render_edit_prediction_end_of_line_popover(
 8320        self: &mut Editor,
 8321        label: &'static str,
 8322        editor_snapshot: &EditorSnapshot,
 8323        visible_row_range: Range<DisplayRow>,
 8324        target_display_point: DisplayPoint,
 8325        line_height: Pixels,
 8326        scroll_pixel_position: gpui::Point<Pixels>,
 8327        content_origin: gpui::Point<Pixels>,
 8328        editor_width: Pixels,
 8329        window: &mut Window,
 8330        cx: &mut App,
 8331    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8332        let target_line_end = DisplayPoint::new(
 8333            target_display_point.row(),
 8334            editor_snapshot.line_len(target_display_point.row()),
 8335        );
 8336
 8337        let mut element = self
 8338            .render_edit_prediction_line_popover(label, None, window, cx)?
 8339            .into_any();
 8340
 8341        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8342
 8343        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8344
 8345        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8346        let mut origin = start_point
 8347            + line_origin
 8348            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8349        origin.x = origin.x.max(content_origin.x);
 8350
 8351        let max_x = content_origin.x + editor_width - size.width;
 8352
 8353        if origin.x > max_x {
 8354            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8355
 8356            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8357                origin.y += offset;
 8358                IconName::ArrowUp
 8359            } else {
 8360                origin.y -= offset;
 8361                IconName::ArrowDown
 8362            };
 8363
 8364            element = self
 8365                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8366                .into_any();
 8367
 8368            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8369
 8370            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8371        }
 8372
 8373        element.prepaint_at(origin, window, cx);
 8374        Some((element, origin))
 8375    }
 8376
 8377    fn render_edit_prediction_diff_popover(
 8378        self: &Editor,
 8379        text_bounds: &Bounds<Pixels>,
 8380        content_origin: gpui::Point<Pixels>,
 8381        right_margin: Pixels,
 8382        editor_snapshot: &EditorSnapshot,
 8383        visible_row_range: Range<DisplayRow>,
 8384        line_layouts: &[LineWithInvisibles],
 8385        line_height: Pixels,
 8386        scroll_pixel_position: gpui::Point<Pixels>,
 8387        newest_selection_head: Option<DisplayPoint>,
 8388        editor_width: Pixels,
 8389        style: &EditorStyle,
 8390        edits: &Vec<(Range<Anchor>, String)>,
 8391        edit_preview: &Option<language::EditPreview>,
 8392        snapshot: &language::BufferSnapshot,
 8393        window: &mut Window,
 8394        cx: &mut App,
 8395    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8396        let edit_start = edits
 8397            .first()
 8398            .unwrap()
 8399            .0
 8400            .start
 8401            .to_display_point(editor_snapshot);
 8402        let edit_end = edits
 8403            .last()
 8404            .unwrap()
 8405            .0
 8406            .end
 8407            .to_display_point(editor_snapshot);
 8408
 8409        let is_visible = visible_row_range.contains(&edit_start.row())
 8410            || visible_row_range.contains(&edit_end.row());
 8411        if !is_visible {
 8412            return None;
 8413        }
 8414
 8415        let highlighted_edits =
 8416            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8417
 8418        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8419        let line_count = highlighted_edits.text.lines().count();
 8420
 8421        const BORDER_WIDTH: Pixels = px(1.);
 8422
 8423        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8424        let has_keybind = keybind.is_some();
 8425
 8426        let mut element = h_flex()
 8427            .items_start()
 8428            .child(
 8429                h_flex()
 8430                    .bg(cx.theme().colors().editor_background)
 8431                    .border(BORDER_WIDTH)
 8432                    .shadow_sm()
 8433                    .border_color(cx.theme().colors().border)
 8434                    .rounded_l_lg()
 8435                    .when(line_count > 1, |el| el.rounded_br_lg())
 8436                    .pr_1()
 8437                    .child(styled_text),
 8438            )
 8439            .child(
 8440                h_flex()
 8441                    .h(line_height + BORDER_WIDTH * 2.)
 8442                    .px_1p5()
 8443                    .gap_1()
 8444                    // Workaround: For some reason, there's a gap if we don't do this
 8445                    .ml(-BORDER_WIDTH)
 8446                    .shadow(vec![gpui::BoxShadow {
 8447                        color: gpui::black().opacity(0.05),
 8448                        offset: point(px(1.), px(1.)),
 8449                        blur_radius: px(2.),
 8450                        spread_radius: px(0.),
 8451                    }])
 8452                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8453                    .border(BORDER_WIDTH)
 8454                    .border_color(cx.theme().colors().border)
 8455                    .rounded_r_lg()
 8456                    .id("edit_prediction_diff_popover_keybind")
 8457                    .when(!has_keybind, |el| {
 8458                        let status_colors = cx.theme().status();
 8459
 8460                        el.bg(status_colors.error_background)
 8461                            .border_color(status_colors.error.opacity(0.6))
 8462                            .child(Icon::new(IconName::Info).color(Color::Error))
 8463                            .cursor_default()
 8464                            .hoverable_tooltip(move |_window, cx| {
 8465                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8466                            })
 8467                    })
 8468                    .children(keybind),
 8469            )
 8470            .into_any();
 8471
 8472        let longest_row =
 8473            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8474        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8475            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8476        } else {
 8477            layout_line(
 8478                longest_row,
 8479                editor_snapshot,
 8480                style,
 8481                editor_width,
 8482                |_| false,
 8483                window,
 8484                cx,
 8485            )
 8486            .width
 8487        };
 8488
 8489        let viewport_bounds =
 8490            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8491                right: -right_margin,
 8492                ..Default::default()
 8493            });
 8494
 8495        let x_after_longest =
 8496            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8497                - scroll_pixel_position.x;
 8498
 8499        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8500
 8501        // Fully visible if it can be displayed within the window (allow overlapping other
 8502        // panes). However, this is only allowed if the popover starts within text_bounds.
 8503        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8504            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8505
 8506        let mut origin = if can_position_to_the_right {
 8507            point(
 8508                x_after_longest,
 8509                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8510                    - scroll_pixel_position.y,
 8511            )
 8512        } else {
 8513            let cursor_row = newest_selection_head.map(|head| head.row());
 8514            let above_edit = edit_start
 8515                .row()
 8516                .0
 8517                .checked_sub(line_count as u32)
 8518                .map(DisplayRow);
 8519            let below_edit = Some(edit_end.row() + 1);
 8520            let above_cursor =
 8521                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8522            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8523
 8524            // Place the edit popover adjacent to the edit if there is a location
 8525            // available that is onscreen and does not obscure the cursor. Otherwise,
 8526            // place it adjacent to the cursor.
 8527            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8528                .into_iter()
 8529                .flatten()
 8530                .find(|&start_row| {
 8531                    let end_row = start_row + line_count as u32;
 8532                    visible_row_range.contains(&start_row)
 8533                        && visible_row_range.contains(&end_row)
 8534                        && cursor_row.map_or(true, |cursor_row| {
 8535                            !((start_row..end_row).contains(&cursor_row))
 8536                        })
 8537                })?;
 8538
 8539            content_origin
 8540                + point(
 8541                    -scroll_pixel_position.x,
 8542                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8543                )
 8544        };
 8545
 8546        origin.x -= BORDER_WIDTH;
 8547
 8548        window.defer_draw(element, origin, 1);
 8549
 8550        // Do not return an element, since it will already be drawn due to defer_draw.
 8551        None
 8552    }
 8553
 8554    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8555        px(30.)
 8556    }
 8557
 8558    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8559        if self.read_only(cx) {
 8560            cx.theme().players().read_only()
 8561        } else {
 8562            self.style.as_ref().unwrap().local_player
 8563        }
 8564    }
 8565
 8566    fn render_edit_prediction_accept_keybind(
 8567        &self,
 8568        window: &mut Window,
 8569        cx: &App,
 8570    ) -> Option<AnyElement> {
 8571        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8572        let accept_keystroke = accept_binding.keystroke()?;
 8573
 8574        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8575
 8576        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8577            Color::Accent
 8578        } else {
 8579            Color::Muted
 8580        };
 8581
 8582        h_flex()
 8583            .px_0p5()
 8584            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8585            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8586            .text_size(TextSize::XSmall.rems(cx))
 8587            .child(h_flex().children(ui::render_modifiers(
 8588                &accept_keystroke.modifiers,
 8589                PlatformStyle::platform(),
 8590                Some(modifiers_color),
 8591                Some(IconSize::XSmall.rems().into()),
 8592                true,
 8593            )))
 8594            .when(is_platform_style_mac, |parent| {
 8595                parent.child(accept_keystroke.key.clone())
 8596            })
 8597            .when(!is_platform_style_mac, |parent| {
 8598                parent.child(
 8599                    Key::new(
 8600                        util::capitalize(&accept_keystroke.key),
 8601                        Some(Color::Default),
 8602                    )
 8603                    .size(Some(IconSize::XSmall.rems().into())),
 8604                )
 8605            })
 8606            .into_any()
 8607            .into()
 8608    }
 8609
 8610    fn render_edit_prediction_line_popover(
 8611        &self,
 8612        label: impl Into<SharedString>,
 8613        icon: Option<IconName>,
 8614        window: &mut Window,
 8615        cx: &App,
 8616    ) -> Option<Stateful<Div>> {
 8617        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8618
 8619        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8620        let has_keybind = keybind.is_some();
 8621
 8622        let result = h_flex()
 8623            .id("ep-line-popover")
 8624            .py_0p5()
 8625            .pl_1()
 8626            .pr(padding_right)
 8627            .gap_1()
 8628            .rounded_md()
 8629            .border_1()
 8630            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8631            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8632            .shadow_sm()
 8633            .when(!has_keybind, |el| {
 8634                let status_colors = cx.theme().status();
 8635
 8636                el.bg(status_colors.error_background)
 8637                    .border_color(status_colors.error.opacity(0.6))
 8638                    .pl_2()
 8639                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8640                    .cursor_default()
 8641                    .hoverable_tooltip(move |_window, cx| {
 8642                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8643                    })
 8644            })
 8645            .children(keybind)
 8646            .child(
 8647                Label::new(label)
 8648                    .size(LabelSize::Small)
 8649                    .when(!has_keybind, |el| {
 8650                        el.color(cx.theme().status().error.into()).strikethrough()
 8651                    }),
 8652            )
 8653            .when(!has_keybind, |el| {
 8654                el.child(
 8655                    h_flex().ml_1().child(
 8656                        Icon::new(IconName::Info)
 8657                            .size(IconSize::Small)
 8658                            .color(cx.theme().status().error.into()),
 8659                    ),
 8660                )
 8661            })
 8662            .when_some(icon, |element, icon| {
 8663                element.child(
 8664                    div()
 8665                        .mt(px(1.5))
 8666                        .child(Icon::new(icon).size(IconSize::Small)),
 8667                )
 8668            });
 8669
 8670        Some(result)
 8671    }
 8672
 8673    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8674        let accent_color = cx.theme().colors().text_accent;
 8675        let editor_bg_color = cx.theme().colors().editor_background;
 8676        editor_bg_color.blend(accent_color.opacity(0.1))
 8677    }
 8678
 8679    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8680        let accent_color = cx.theme().colors().text_accent;
 8681        let editor_bg_color = cx.theme().colors().editor_background;
 8682        editor_bg_color.blend(accent_color.opacity(0.6))
 8683    }
 8684
 8685    fn render_edit_prediction_cursor_popover(
 8686        &self,
 8687        min_width: Pixels,
 8688        max_width: Pixels,
 8689        cursor_point: Point,
 8690        style: &EditorStyle,
 8691        accept_keystroke: Option<&gpui::Keystroke>,
 8692        _window: &Window,
 8693        cx: &mut Context<Editor>,
 8694    ) -> Option<AnyElement> {
 8695        let provider = self.edit_prediction_provider.as_ref()?;
 8696
 8697        if provider.provider.needs_terms_acceptance(cx) {
 8698            return Some(
 8699                h_flex()
 8700                    .min_w(min_width)
 8701                    .flex_1()
 8702                    .px_2()
 8703                    .py_1()
 8704                    .gap_3()
 8705                    .elevation_2(cx)
 8706                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8707                    .id("accept-terms")
 8708                    .cursor_pointer()
 8709                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8710                    .on_click(cx.listener(|this, _event, window, cx| {
 8711                        cx.stop_propagation();
 8712                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8713                        window.dispatch_action(
 8714                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8715                            cx,
 8716                        );
 8717                    }))
 8718                    .child(
 8719                        h_flex()
 8720                            .flex_1()
 8721                            .gap_2()
 8722                            .child(Icon::new(IconName::ZedPredict))
 8723                            .child(Label::new("Accept Terms of Service"))
 8724                            .child(div().w_full())
 8725                            .child(
 8726                                Icon::new(IconName::ArrowUpRight)
 8727                                    .color(Color::Muted)
 8728                                    .size(IconSize::Small),
 8729                            )
 8730                            .into_any_element(),
 8731                    )
 8732                    .into_any(),
 8733            );
 8734        }
 8735
 8736        let is_refreshing = provider.provider.is_refreshing(cx);
 8737
 8738        fn pending_completion_container() -> Div {
 8739            h_flex()
 8740                .h_full()
 8741                .flex_1()
 8742                .gap_2()
 8743                .child(Icon::new(IconName::ZedPredict))
 8744        }
 8745
 8746        let completion = match &self.active_inline_completion {
 8747            Some(prediction) => {
 8748                if !self.has_visible_completions_menu() {
 8749                    const RADIUS: Pixels = px(6.);
 8750                    const BORDER_WIDTH: Pixels = px(1.);
 8751
 8752                    return Some(
 8753                        h_flex()
 8754                            .elevation_2(cx)
 8755                            .border(BORDER_WIDTH)
 8756                            .border_color(cx.theme().colors().border)
 8757                            .when(accept_keystroke.is_none(), |el| {
 8758                                el.border_color(cx.theme().status().error)
 8759                            })
 8760                            .rounded(RADIUS)
 8761                            .rounded_tl(px(0.))
 8762                            .overflow_hidden()
 8763                            .child(div().px_1p5().child(match &prediction.completion {
 8764                                InlineCompletion::Move { target, snapshot } => {
 8765                                    use text::ToPoint as _;
 8766                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8767                                    {
 8768                                        Icon::new(IconName::ZedPredictDown)
 8769                                    } else {
 8770                                        Icon::new(IconName::ZedPredictUp)
 8771                                    }
 8772                                }
 8773                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8774                            }))
 8775                            .child(
 8776                                h_flex()
 8777                                    .gap_1()
 8778                                    .py_1()
 8779                                    .px_2()
 8780                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8781                                    .border_l_1()
 8782                                    .border_color(cx.theme().colors().border)
 8783                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8784                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8785                                        el.child(
 8786                                            Label::new("Hold")
 8787                                                .size(LabelSize::Small)
 8788                                                .when(accept_keystroke.is_none(), |el| {
 8789                                                    el.strikethrough()
 8790                                                })
 8791                                                .line_height_style(LineHeightStyle::UiLabel),
 8792                                        )
 8793                                    })
 8794                                    .id("edit_prediction_cursor_popover_keybind")
 8795                                    .when(accept_keystroke.is_none(), |el| {
 8796                                        let status_colors = cx.theme().status();
 8797
 8798                                        el.bg(status_colors.error_background)
 8799                                            .border_color(status_colors.error.opacity(0.6))
 8800                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8801                                            .cursor_default()
 8802                                            .hoverable_tooltip(move |_window, cx| {
 8803                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8804                                                    .into()
 8805                                            })
 8806                                    })
 8807                                    .when_some(
 8808                                        accept_keystroke.as_ref(),
 8809                                        |el, accept_keystroke| {
 8810                                            el.child(h_flex().children(ui::render_modifiers(
 8811                                                &accept_keystroke.modifiers,
 8812                                                PlatformStyle::platform(),
 8813                                                Some(Color::Default),
 8814                                                Some(IconSize::XSmall.rems().into()),
 8815                                                false,
 8816                                            )))
 8817                                        },
 8818                                    ),
 8819                            )
 8820                            .into_any(),
 8821                    );
 8822                }
 8823
 8824                self.render_edit_prediction_cursor_popover_preview(
 8825                    prediction,
 8826                    cursor_point,
 8827                    style,
 8828                    cx,
 8829                )?
 8830            }
 8831
 8832            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8833                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8834                    stale_completion,
 8835                    cursor_point,
 8836                    style,
 8837                    cx,
 8838                )?,
 8839
 8840                None => {
 8841                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8842                }
 8843            },
 8844
 8845            None => pending_completion_container().child(Label::new("No Prediction")),
 8846        };
 8847
 8848        let completion = if is_refreshing {
 8849            completion
 8850                .with_animation(
 8851                    "loading-completion",
 8852                    Animation::new(Duration::from_secs(2))
 8853                        .repeat()
 8854                        .with_easing(pulsating_between(0.4, 0.8)),
 8855                    |label, delta| label.opacity(delta),
 8856                )
 8857                .into_any_element()
 8858        } else {
 8859            completion.into_any_element()
 8860        };
 8861
 8862        let has_completion = self.active_inline_completion.is_some();
 8863
 8864        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8865        Some(
 8866            h_flex()
 8867                .min_w(min_width)
 8868                .max_w(max_width)
 8869                .flex_1()
 8870                .elevation_2(cx)
 8871                .border_color(cx.theme().colors().border)
 8872                .child(
 8873                    div()
 8874                        .flex_1()
 8875                        .py_1()
 8876                        .px_2()
 8877                        .overflow_hidden()
 8878                        .child(completion),
 8879                )
 8880                .when_some(accept_keystroke, |el, accept_keystroke| {
 8881                    if !accept_keystroke.modifiers.modified() {
 8882                        return el;
 8883                    }
 8884
 8885                    el.child(
 8886                        h_flex()
 8887                            .h_full()
 8888                            .border_l_1()
 8889                            .rounded_r_lg()
 8890                            .border_color(cx.theme().colors().border)
 8891                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8892                            .gap_1()
 8893                            .py_1()
 8894                            .px_2()
 8895                            .child(
 8896                                h_flex()
 8897                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8898                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8899                                    .child(h_flex().children(ui::render_modifiers(
 8900                                        &accept_keystroke.modifiers,
 8901                                        PlatformStyle::platform(),
 8902                                        Some(if !has_completion {
 8903                                            Color::Muted
 8904                                        } else {
 8905                                            Color::Default
 8906                                        }),
 8907                                        None,
 8908                                        false,
 8909                                    ))),
 8910                            )
 8911                            .child(Label::new("Preview").into_any_element())
 8912                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8913                    )
 8914                })
 8915                .into_any(),
 8916        )
 8917    }
 8918
 8919    fn render_edit_prediction_cursor_popover_preview(
 8920        &self,
 8921        completion: &InlineCompletionState,
 8922        cursor_point: Point,
 8923        style: &EditorStyle,
 8924        cx: &mut Context<Editor>,
 8925    ) -> Option<Div> {
 8926        use text::ToPoint as _;
 8927
 8928        fn render_relative_row_jump(
 8929            prefix: impl Into<String>,
 8930            current_row: u32,
 8931            target_row: u32,
 8932        ) -> Div {
 8933            let (row_diff, arrow) = if target_row < current_row {
 8934                (current_row - target_row, IconName::ArrowUp)
 8935            } else {
 8936                (target_row - current_row, IconName::ArrowDown)
 8937            };
 8938
 8939            h_flex()
 8940                .child(
 8941                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8942                        .color(Color::Muted)
 8943                        .size(LabelSize::Small),
 8944                )
 8945                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8946        }
 8947
 8948        match &completion.completion {
 8949            InlineCompletion::Move {
 8950                target, snapshot, ..
 8951            } => Some(
 8952                h_flex()
 8953                    .px_2()
 8954                    .gap_2()
 8955                    .flex_1()
 8956                    .child(
 8957                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8958                            Icon::new(IconName::ZedPredictDown)
 8959                        } else {
 8960                            Icon::new(IconName::ZedPredictUp)
 8961                        },
 8962                    )
 8963                    .child(Label::new("Jump to Edit")),
 8964            ),
 8965
 8966            InlineCompletion::Edit {
 8967                edits,
 8968                edit_preview,
 8969                snapshot,
 8970                display_mode: _,
 8971            } => {
 8972                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8973
 8974                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8975                    &snapshot,
 8976                    &edits,
 8977                    edit_preview.as_ref()?,
 8978                    true,
 8979                    cx,
 8980                )
 8981                .first_line_preview();
 8982
 8983                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8984                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8985
 8986                let preview = h_flex()
 8987                    .gap_1()
 8988                    .min_w_16()
 8989                    .child(styled_text)
 8990                    .when(has_more_lines, |parent| parent.child(""));
 8991
 8992                let left = if first_edit_row != cursor_point.row {
 8993                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8994                        .into_any_element()
 8995                } else {
 8996                    Icon::new(IconName::ZedPredict).into_any_element()
 8997                };
 8998
 8999                Some(
 9000                    h_flex()
 9001                        .h_full()
 9002                        .flex_1()
 9003                        .gap_2()
 9004                        .pr_1()
 9005                        .overflow_x_hidden()
 9006                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9007                        .child(left)
 9008                        .child(preview),
 9009                )
 9010            }
 9011        }
 9012    }
 9013
 9014    pub fn render_context_menu(
 9015        &self,
 9016        style: &EditorStyle,
 9017        max_height_in_lines: u32,
 9018        window: &mut Window,
 9019        cx: &mut Context<Editor>,
 9020    ) -> Option<AnyElement> {
 9021        let menu = self.context_menu.borrow();
 9022        let menu = menu.as_ref()?;
 9023        if !menu.visible() {
 9024            return None;
 9025        };
 9026        Some(menu.render(style, max_height_in_lines, window, cx))
 9027    }
 9028
 9029    fn render_context_menu_aside(
 9030        &mut self,
 9031        max_size: Size<Pixels>,
 9032        window: &mut Window,
 9033        cx: &mut Context<Editor>,
 9034    ) -> Option<AnyElement> {
 9035        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9036            if menu.visible() {
 9037                menu.render_aside(max_size, window, cx)
 9038            } else {
 9039                None
 9040            }
 9041        })
 9042    }
 9043
 9044    fn hide_context_menu(
 9045        &mut self,
 9046        window: &mut Window,
 9047        cx: &mut Context<Self>,
 9048    ) -> Option<CodeContextMenu> {
 9049        cx.notify();
 9050        self.completion_tasks.clear();
 9051        let context_menu = self.context_menu.borrow_mut().take();
 9052        self.stale_inline_completion_in_menu.take();
 9053        self.update_visible_inline_completion(window, cx);
 9054        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9055            if let Some(completion_provider) = &self.completion_provider {
 9056                completion_provider.selection_changed(None, window, cx);
 9057            }
 9058        }
 9059        context_menu
 9060    }
 9061
 9062    fn show_snippet_choices(
 9063        &mut self,
 9064        choices: &Vec<String>,
 9065        selection: Range<Anchor>,
 9066        cx: &mut Context<Self>,
 9067    ) {
 9068        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9069            (Some(a), Some(b)) if a == b => a,
 9070            _ => {
 9071                log::error!("expected anchor range to have matching buffer IDs");
 9072                return;
 9073            }
 9074        };
 9075        let multi_buffer = self.buffer().read(cx);
 9076        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9077            return;
 9078        };
 9079
 9080        let id = post_inc(&mut self.next_completion_id);
 9081        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9082        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9083            CompletionsMenu::new_snippet_choices(
 9084                id,
 9085                true,
 9086                choices,
 9087                selection,
 9088                buffer,
 9089                snippet_sort_order,
 9090            ),
 9091        ));
 9092    }
 9093
 9094    pub fn insert_snippet(
 9095        &mut self,
 9096        insertion_ranges: &[Range<usize>],
 9097        snippet: Snippet,
 9098        window: &mut Window,
 9099        cx: &mut Context<Self>,
 9100    ) -> Result<()> {
 9101        struct Tabstop<T> {
 9102            is_end_tabstop: bool,
 9103            ranges: Vec<Range<T>>,
 9104            choices: Option<Vec<String>>,
 9105        }
 9106
 9107        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9108            let snippet_text: Arc<str> = snippet.text.clone().into();
 9109            let edits = insertion_ranges
 9110                .iter()
 9111                .cloned()
 9112                .map(|range| (range, snippet_text.clone()));
 9113            let autoindent_mode = AutoindentMode::Block {
 9114                original_indent_columns: Vec::new(),
 9115            };
 9116            buffer.edit(edits, Some(autoindent_mode), cx);
 9117
 9118            let snapshot = &*buffer.read(cx);
 9119            let snippet = &snippet;
 9120            snippet
 9121                .tabstops
 9122                .iter()
 9123                .map(|tabstop| {
 9124                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9125                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9126                    });
 9127                    let mut tabstop_ranges = tabstop
 9128                        .ranges
 9129                        .iter()
 9130                        .flat_map(|tabstop_range| {
 9131                            let mut delta = 0_isize;
 9132                            insertion_ranges.iter().map(move |insertion_range| {
 9133                                let insertion_start = insertion_range.start as isize + delta;
 9134                                delta +=
 9135                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9136
 9137                                let start = ((insertion_start + tabstop_range.start) as usize)
 9138                                    .min(snapshot.len());
 9139                                let end = ((insertion_start + tabstop_range.end) as usize)
 9140                                    .min(snapshot.len());
 9141                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9142                            })
 9143                        })
 9144                        .collect::<Vec<_>>();
 9145                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9146
 9147                    Tabstop {
 9148                        is_end_tabstop,
 9149                        ranges: tabstop_ranges,
 9150                        choices: tabstop.choices.clone(),
 9151                    }
 9152                })
 9153                .collect::<Vec<_>>()
 9154        });
 9155        if let Some(tabstop) = tabstops.first() {
 9156            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9157                // Reverse order so that the first range is the newest created selection.
 9158                // Completions will use it and autoscroll will prioritize it.
 9159                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9160            });
 9161
 9162            if let Some(choices) = &tabstop.choices {
 9163                if let Some(selection) = tabstop.ranges.first() {
 9164                    self.show_snippet_choices(choices, selection.clone(), cx)
 9165                }
 9166            }
 9167
 9168            // If we're already at the last tabstop and it's at the end of the snippet,
 9169            // we're done, we don't need to keep the state around.
 9170            if !tabstop.is_end_tabstop {
 9171                let choices = tabstops
 9172                    .iter()
 9173                    .map(|tabstop| tabstop.choices.clone())
 9174                    .collect();
 9175
 9176                let ranges = tabstops
 9177                    .into_iter()
 9178                    .map(|tabstop| tabstop.ranges)
 9179                    .collect::<Vec<_>>();
 9180
 9181                self.snippet_stack.push(SnippetState {
 9182                    active_index: 0,
 9183                    ranges,
 9184                    choices,
 9185                });
 9186            }
 9187
 9188            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9189            if self.autoclose_regions.is_empty() {
 9190                let snapshot = self.buffer.read(cx).snapshot(cx);
 9191                for selection in &mut self.selections.all::<Point>(cx) {
 9192                    let selection_head = selection.head();
 9193                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9194                        continue;
 9195                    };
 9196
 9197                    let mut bracket_pair = None;
 9198                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9199                    let prev_chars = snapshot
 9200                        .reversed_chars_at(selection_head)
 9201                        .collect::<String>();
 9202                    for (pair, enabled) in scope.brackets() {
 9203                        if enabled
 9204                            && pair.close
 9205                            && prev_chars.starts_with(pair.start.as_str())
 9206                            && next_chars.starts_with(pair.end.as_str())
 9207                        {
 9208                            bracket_pair = Some(pair.clone());
 9209                            break;
 9210                        }
 9211                    }
 9212                    if let Some(pair) = bracket_pair {
 9213                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9214                        let autoclose_enabled =
 9215                            self.use_autoclose && snapshot_settings.use_autoclose;
 9216                        if autoclose_enabled {
 9217                            let start = snapshot.anchor_after(selection_head);
 9218                            let end = snapshot.anchor_after(selection_head);
 9219                            self.autoclose_regions.push(AutocloseRegion {
 9220                                selection_id: selection.id,
 9221                                range: start..end,
 9222                                pair,
 9223                            });
 9224                        }
 9225                    }
 9226                }
 9227            }
 9228        }
 9229        Ok(())
 9230    }
 9231
 9232    pub fn move_to_next_snippet_tabstop(
 9233        &mut self,
 9234        window: &mut Window,
 9235        cx: &mut Context<Self>,
 9236    ) -> bool {
 9237        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9238    }
 9239
 9240    pub fn move_to_prev_snippet_tabstop(
 9241        &mut self,
 9242        window: &mut Window,
 9243        cx: &mut Context<Self>,
 9244    ) -> bool {
 9245        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9246    }
 9247
 9248    pub fn move_to_snippet_tabstop(
 9249        &mut self,
 9250        bias: Bias,
 9251        window: &mut Window,
 9252        cx: &mut Context<Self>,
 9253    ) -> bool {
 9254        if let Some(mut snippet) = self.snippet_stack.pop() {
 9255            match bias {
 9256                Bias::Left => {
 9257                    if snippet.active_index > 0 {
 9258                        snippet.active_index -= 1;
 9259                    } else {
 9260                        self.snippet_stack.push(snippet);
 9261                        return false;
 9262                    }
 9263                }
 9264                Bias::Right => {
 9265                    if snippet.active_index + 1 < snippet.ranges.len() {
 9266                        snippet.active_index += 1;
 9267                    } else {
 9268                        self.snippet_stack.push(snippet);
 9269                        return false;
 9270                    }
 9271                }
 9272            }
 9273            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9274                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9275                    // Reverse order so that the first range is the newest created selection.
 9276                    // Completions will use it and autoscroll will prioritize it.
 9277                    s.select_ranges(current_ranges.iter().rev().cloned())
 9278                });
 9279
 9280                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9281                    if let Some(selection) = current_ranges.first() {
 9282                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9283                    }
 9284                }
 9285
 9286                // If snippet state is not at the last tabstop, push it back on the stack
 9287                if snippet.active_index + 1 < snippet.ranges.len() {
 9288                    self.snippet_stack.push(snippet);
 9289                }
 9290                return true;
 9291            }
 9292        }
 9293
 9294        false
 9295    }
 9296
 9297    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9298        self.transact(window, cx, |this, window, cx| {
 9299            this.select_all(&SelectAll, window, cx);
 9300            this.insert("", window, cx);
 9301        });
 9302    }
 9303
 9304    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9305        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9306        self.transact(window, cx, |this, window, cx| {
 9307            this.select_autoclose_pair(window, cx);
 9308            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9309            if !this.linked_edit_ranges.is_empty() {
 9310                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9311                let snapshot = this.buffer.read(cx).snapshot(cx);
 9312
 9313                for selection in selections.iter() {
 9314                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9315                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9316                    if selection_start.buffer_id != selection_end.buffer_id {
 9317                        continue;
 9318                    }
 9319                    if let Some(ranges) =
 9320                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9321                    {
 9322                        for (buffer, entries) in ranges {
 9323                            linked_ranges.entry(buffer).or_default().extend(entries);
 9324                        }
 9325                    }
 9326                }
 9327            }
 9328
 9329            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9330            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9331            for selection in &mut selections {
 9332                if selection.is_empty() {
 9333                    let old_head = selection.head();
 9334                    let mut new_head =
 9335                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9336                            .to_point(&display_map);
 9337                    if let Some((buffer, line_buffer_range)) = display_map
 9338                        .buffer_snapshot
 9339                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9340                    {
 9341                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9342                        let indent_len = match indent_size.kind {
 9343                            IndentKind::Space => {
 9344                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9345                            }
 9346                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9347                        };
 9348                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9349                            let indent_len = indent_len.get();
 9350                            new_head = cmp::min(
 9351                                new_head,
 9352                                MultiBufferPoint::new(
 9353                                    old_head.row,
 9354                                    ((old_head.column - 1) / indent_len) * indent_len,
 9355                                ),
 9356                            );
 9357                        }
 9358                    }
 9359
 9360                    selection.set_head(new_head, SelectionGoal::None);
 9361                }
 9362            }
 9363
 9364            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9365                s.select(selections)
 9366            });
 9367            this.insert("", window, cx);
 9368            let empty_str: Arc<str> = Arc::from("");
 9369            for (buffer, edits) in linked_ranges {
 9370                let snapshot = buffer.read(cx).snapshot();
 9371                use text::ToPoint as TP;
 9372
 9373                let edits = edits
 9374                    .into_iter()
 9375                    .map(|range| {
 9376                        let end_point = TP::to_point(&range.end, &snapshot);
 9377                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9378
 9379                        if end_point == start_point {
 9380                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9381                                .saturating_sub(1);
 9382                            start_point =
 9383                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9384                        };
 9385
 9386                        (start_point..end_point, empty_str.clone())
 9387                    })
 9388                    .sorted_by_key(|(range, _)| range.start)
 9389                    .collect::<Vec<_>>();
 9390                buffer.update(cx, |this, cx| {
 9391                    this.edit(edits, None, cx);
 9392                })
 9393            }
 9394            this.refresh_inline_completion(true, false, window, cx);
 9395            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9396        });
 9397    }
 9398
 9399    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9400        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9401        self.transact(window, cx, |this, window, cx| {
 9402            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9403                s.move_with(|map, selection| {
 9404                    if selection.is_empty() {
 9405                        let cursor = movement::right(map, selection.head());
 9406                        selection.end = cursor;
 9407                        selection.reversed = true;
 9408                        selection.goal = SelectionGoal::None;
 9409                    }
 9410                })
 9411            });
 9412            this.insert("", window, cx);
 9413            this.refresh_inline_completion(true, false, window, cx);
 9414        });
 9415    }
 9416
 9417    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9418        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9419        if self.move_to_prev_snippet_tabstop(window, cx) {
 9420            return;
 9421        }
 9422        self.outdent(&Outdent, window, cx);
 9423    }
 9424
 9425    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9426        if self.move_to_next_snippet_tabstop(window, cx) {
 9427            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9428            return;
 9429        }
 9430        if self.read_only(cx) {
 9431            return;
 9432        }
 9433        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9434        let mut selections = self.selections.all_adjusted(cx);
 9435        let buffer = self.buffer.read(cx);
 9436        let snapshot = buffer.snapshot(cx);
 9437        let rows_iter = selections.iter().map(|s| s.head().row);
 9438        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9439
 9440        let has_some_cursor_in_whitespace = selections
 9441            .iter()
 9442            .filter(|selection| selection.is_empty())
 9443            .any(|selection| {
 9444                let cursor = selection.head();
 9445                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9446                cursor.column < current_indent.len
 9447            });
 9448
 9449        let mut edits = Vec::new();
 9450        let mut prev_edited_row = 0;
 9451        let mut row_delta = 0;
 9452        for selection in &mut selections {
 9453            if selection.start.row != prev_edited_row {
 9454                row_delta = 0;
 9455            }
 9456            prev_edited_row = selection.end.row;
 9457
 9458            // If the selection is non-empty, then increase the indentation of the selected lines.
 9459            if !selection.is_empty() {
 9460                row_delta =
 9461                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9462                continue;
 9463            }
 9464
 9465            let cursor = selection.head();
 9466            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9467            if let Some(suggested_indent) =
 9468                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9469            {
 9470                // Don't do anything if already at suggested indent
 9471                // and there is any other cursor which is not
 9472                if has_some_cursor_in_whitespace
 9473                    && cursor.column == current_indent.len
 9474                    && current_indent.len == suggested_indent.len
 9475                {
 9476                    continue;
 9477                }
 9478
 9479                // Adjust line and move cursor to suggested indent
 9480                // if cursor is not at suggested indent
 9481                if cursor.column < suggested_indent.len
 9482                    && cursor.column <= current_indent.len
 9483                    && current_indent.len <= suggested_indent.len
 9484                {
 9485                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9486                    selection.end = selection.start;
 9487                    if row_delta == 0 {
 9488                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9489                            cursor.row,
 9490                            current_indent,
 9491                            suggested_indent,
 9492                        ));
 9493                        row_delta = suggested_indent.len - current_indent.len;
 9494                    }
 9495                    continue;
 9496                }
 9497
 9498                // If current indent is more than suggested indent
 9499                // only move cursor to current indent and skip indent
 9500                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9501                    selection.start = Point::new(cursor.row, current_indent.len);
 9502                    selection.end = selection.start;
 9503                    continue;
 9504                }
 9505            }
 9506
 9507            // Otherwise, insert a hard or soft tab.
 9508            let settings = buffer.language_settings_at(cursor, cx);
 9509            let tab_size = if settings.hard_tabs {
 9510                IndentSize::tab()
 9511            } else {
 9512                let tab_size = settings.tab_size.get();
 9513                let indent_remainder = snapshot
 9514                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9515                    .flat_map(str::chars)
 9516                    .fold(row_delta % tab_size, |counter: u32, c| {
 9517                        if c == '\t' {
 9518                            0
 9519                        } else {
 9520                            (counter + 1) % tab_size
 9521                        }
 9522                    });
 9523
 9524                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9525                IndentSize::spaces(chars_to_next_tab_stop)
 9526            };
 9527            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9528            selection.end = selection.start;
 9529            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9530            row_delta += tab_size.len;
 9531        }
 9532
 9533        self.transact(window, cx, |this, window, cx| {
 9534            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9535            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9536                s.select(selections)
 9537            });
 9538            this.refresh_inline_completion(true, false, window, cx);
 9539        });
 9540    }
 9541
 9542    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9543        if self.read_only(cx) {
 9544            return;
 9545        }
 9546        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9547        let mut selections = self.selections.all::<Point>(cx);
 9548        let mut prev_edited_row = 0;
 9549        let mut row_delta = 0;
 9550        let mut edits = Vec::new();
 9551        let buffer = self.buffer.read(cx);
 9552        let snapshot = buffer.snapshot(cx);
 9553        for selection in &mut selections {
 9554            if selection.start.row != prev_edited_row {
 9555                row_delta = 0;
 9556            }
 9557            prev_edited_row = selection.end.row;
 9558
 9559            row_delta =
 9560                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9561        }
 9562
 9563        self.transact(window, cx, |this, window, cx| {
 9564            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9565            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9566                s.select(selections)
 9567            });
 9568        });
 9569    }
 9570
 9571    fn indent_selection(
 9572        buffer: &MultiBuffer,
 9573        snapshot: &MultiBufferSnapshot,
 9574        selection: &mut Selection<Point>,
 9575        edits: &mut Vec<(Range<Point>, String)>,
 9576        delta_for_start_row: u32,
 9577        cx: &App,
 9578    ) -> u32 {
 9579        let settings = buffer.language_settings_at(selection.start, cx);
 9580        let tab_size = settings.tab_size.get();
 9581        let indent_kind = if settings.hard_tabs {
 9582            IndentKind::Tab
 9583        } else {
 9584            IndentKind::Space
 9585        };
 9586        let mut start_row = selection.start.row;
 9587        let mut end_row = selection.end.row + 1;
 9588
 9589        // If a selection ends at the beginning of a line, don't indent
 9590        // that last line.
 9591        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9592            end_row -= 1;
 9593        }
 9594
 9595        // Avoid re-indenting a row that has already been indented by a
 9596        // previous selection, but still update this selection's column
 9597        // to reflect that indentation.
 9598        if delta_for_start_row > 0 {
 9599            start_row += 1;
 9600            selection.start.column += delta_for_start_row;
 9601            if selection.end.row == selection.start.row {
 9602                selection.end.column += delta_for_start_row;
 9603            }
 9604        }
 9605
 9606        let mut delta_for_end_row = 0;
 9607        let has_multiple_rows = start_row + 1 != end_row;
 9608        for row in start_row..end_row {
 9609            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9610            let indent_delta = match (current_indent.kind, indent_kind) {
 9611                (IndentKind::Space, IndentKind::Space) => {
 9612                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9613                    IndentSize::spaces(columns_to_next_tab_stop)
 9614                }
 9615                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9616                (_, IndentKind::Tab) => IndentSize::tab(),
 9617            };
 9618
 9619            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9620                0
 9621            } else {
 9622                selection.start.column
 9623            };
 9624            let row_start = Point::new(row, start);
 9625            edits.push((
 9626                row_start..row_start,
 9627                indent_delta.chars().collect::<String>(),
 9628            ));
 9629
 9630            // Update this selection's endpoints to reflect the indentation.
 9631            if row == selection.start.row {
 9632                selection.start.column += indent_delta.len;
 9633            }
 9634            if row == selection.end.row {
 9635                selection.end.column += indent_delta.len;
 9636                delta_for_end_row = indent_delta.len;
 9637            }
 9638        }
 9639
 9640        if selection.start.row == selection.end.row {
 9641            delta_for_start_row + delta_for_end_row
 9642        } else {
 9643            delta_for_end_row
 9644        }
 9645    }
 9646
 9647    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9648        if self.read_only(cx) {
 9649            return;
 9650        }
 9651        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9653        let selections = self.selections.all::<Point>(cx);
 9654        let mut deletion_ranges = Vec::new();
 9655        let mut last_outdent = None;
 9656        {
 9657            let buffer = self.buffer.read(cx);
 9658            let snapshot = buffer.snapshot(cx);
 9659            for selection in &selections {
 9660                let settings = buffer.language_settings_at(selection.start, cx);
 9661                let tab_size = settings.tab_size.get();
 9662                let mut rows = selection.spanned_rows(false, &display_map);
 9663
 9664                // Avoid re-outdenting a row that has already been outdented by a
 9665                // previous selection.
 9666                if let Some(last_row) = last_outdent {
 9667                    if last_row == rows.start {
 9668                        rows.start = rows.start.next_row();
 9669                    }
 9670                }
 9671                let has_multiple_rows = rows.len() > 1;
 9672                for row in rows.iter_rows() {
 9673                    let indent_size = snapshot.indent_size_for_line(row);
 9674                    if indent_size.len > 0 {
 9675                        let deletion_len = match indent_size.kind {
 9676                            IndentKind::Space => {
 9677                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9678                                if columns_to_prev_tab_stop == 0 {
 9679                                    tab_size
 9680                                } else {
 9681                                    columns_to_prev_tab_stop
 9682                                }
 9683                            }
 9684                            IndentKind::Tab => 1,
 9685                        };
 9686                        let start = if has_multiple_rows
 9687                            || deletion_len > selection.start.column
 9688                            || indent_size.len < selection.start.column
 9689                        {
 9690                            0
 9691                        } else {
 9692                            selection.start.column - deletion_len
 9693                        };
 9694                        deletion_ranges.push(
 9695                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9696                        );
 9697                        last_outdent = Some(row);
 9698                    }
 9699                }
 9700            }
 9701        }
 9702
 9703        self.transact(window, cx, |this, window, cx| {
 9704            this.buffer.update(cx, |buffer, cx| {
 9705                let empty_str: Arc<str> = Arc::default();
 9706                buffer.edit(
 9707                    deletion_ranges
 9708                        .into_iter()
 9709                        .map(|range| (range, empty_str.clone())),
 9710                    None,
 9711                    cx,
 9712                );
 9713            });
 9714            let selections = this.selections.all::<usize>(cx);
 9715            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9716                s.select(selections)
 9717            });
 9718        });
 9719    }
 9720
 9721    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9722        if self.read_only(cx) {
 9723            return;
 9724        }
 9725        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9726        let selections = self
 9727            .selections
 9728            .all::<usize>(cx)
 9729            .into_iter()
 9730            .map(|s| s.range());
 9731
 9732        self.transact(window, cx, |this, window, cx| {
 9733            this.buffer.update(cx, |buffer, cx| {
 9734                buffer.autoindent_ranges(selections, cx);
 9735            });
 9736            let selections = this.selections.all::<usize>(cx);
 9737            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9738                s.select(selections)
 9739            });
 9740        });
 9741    }
 9742
 9743    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9744        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9745        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9746        let selections = self.selections.all::<Point>(cx);
 9747
 9748        let mut new_cursors = Vec::new();
 9749        let mut edit_ranges = Vec::new();
 9750        let mut selections = selections.iter().peekable();
 9751        while let Some(selection) = selections.next() {
 9752            let mut rows = selection.spanned_rows(false, &display_map);
 9753            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9754
 9755            // Accumulate contiguous regions of rows that we want to delete.
 9756            while let Some(next_selection) = selections.peek() {
 9757                let next_rows = next_selection.spanned_rows(false, &display_map);
 9758                if next_rows.start <= rows.end {
 9759                    rows.end = next_rows.end;
 9760                    selections.next().unwrap();
 9761                } else {
 9762                    break;
 9763                }
 9764            }
 9765
 9766            let buffer = &display_map.buffer_snapshot;
 9767            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9768            let edit_end;
 9769            let cursor_buffer_row;
 9770            if buffer.max_point().row >= rows.end.0 {
 9771                // If there's a line after the range, delete the \n from the end of the row range
 9772                // and position the cursor on the next line.
 9773                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9774                cursor_buffer_row = rows.end;
 9775            } else {
 9776                // If there isn't a line after the range, delete the \n from the line before the
 9777                // start of the row range and position the cursor there.
 9778                edit_start = edit_start.saturating_sub(1);
 9779                edit_end = buffer.len();
 9780                cursor_buffer_row = rows.start.previous_row();
 9781            }
 9782
 9783            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9784            *cursor.column_mut() =
 9785                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9786
 9787            new_cursors.push((
 9788                selection.id,
 9789                buffer.anchor_after(cursor.to_point(&display_map)),
 9790            ));
 9791            edit_ranges.push(edit_start..edit_end);
 9792        }
 9793
 9794        self.transact(window, cx, |this, window, cx| {
 9795            let buffer = this.buffer.update(cx, |buffer, cx| {
 9796                let empty_str: Arc<str> = Arc::default();
 9797                buffer.edit(
 9798                    edit_ranges
 9799                        .into_iter()
 9800                        .map(|range| (range, empty_str.clone())),
 9801                    None,
 9802                    cx,
 9803                );
 9804                buffer.snapshot(cx)
 9805            });
 9806            let new_selections = new_cursors
 9807                .into_iter()
 9808                .map(|(id, cursor)| {
 9809                    let cursor = cursor.to_point(&buffer);
 9810                    Selection {
 9811                        id,
 9812                        start: cursor,
 9813                        end: cursor,
 9814                        reversed: false,
 9815                        goal: SelectionGoal::None,
 9816                    }
 9817                })
 9818                .collect();
 9819
 9820            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9821                s.select(new_selections);
 9822            });
 9823        });
 9824    }
 9825
 9826    pub fn join_lines_impl(
 9827        &mut self,
 9828        insert_whitespace: bool,
 9829        window: &mut Window,
 9830        cx: &mut Context<Self>,
 9831    ) {
 9832        if self.read_only(cx) {
 9833            return;
 9834        }
 9835        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9836        for selection in self.selections.all::<Point>(cx) {
 9837            let start = MultiBufferRow(selection.start.row);
 9838            // Treat single line selections as if they include the next line. Otherwise this action
 9839            // would do nothing for single line selections individual cursors.
 9840            let end = if selection.start.row == selection.end.row {
 9841                MultiBufferRow(selection.start.row + 1)
 9842            } else {
 9843                MultiBufferRow(selection.end.row)
 9844            };
 9845
 9846            if let Some(last_row_range) = row_ranges.last_mut() {
 9847                if start <= last_row_range.end {
 9848                    last_row_range.end = end;
 9849                    continue;
 9850                }
 9851            }
 9852            row_ranges.push(start..end);
 9853        }
 9854
 9855        let snapshot = self.buffer.read(cx).snapshot(cx);
 9856        let mut cursor_positions = Vec::new();
 9857        for row_range in &row_ranges {
 9858            let anchor = snapshot.anchor_before(Point::new(
 9859                row_range.end.previous_row().0,
 9860                snapshot.line_len(row_range.end.previous_row()),
 9861            ));
 9862            cursor_positions.push(anchor..anchor);
 9863        }
 9864
 9865        self.transact(window, cx, |this, window, cx| {
 9866            for row_range in row_ranges.into_iter().rev() {
 9867                for row in row_range.iter_rows().rev() {
 9868                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9869                    let next_line_row = row.next_row();
 9870                    let indent = snapshot.indent_size_for_line(next_line_row);
 9871                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9872
 9873                    let replace =
 9874                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9875                            " "
 9876                        } else {
 9877                            ""
 9878                        };
 9879
 9880                    this.buffer.update(cx, |buffer, cx| {
 9881                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9882                    });
 9883                }
 9884            }
 9885
 9886            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9887                s.select_anchor_ranges(cursor_positions)
 9888            });
 9889        });
 9890    }
 9891
 9892    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9893        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9894        self.join_lines_impl(true, window, cx);
 9895    }
 9896
 9897    pub fn sort_lines_case_sensitive(
 9898        &mut self,
 9899        _: &SortLinesCaseSensitive,
 9900        window: &mut Window,
 9901        cx: &mut Context<Self>,
 9902    ) {
 9903        self.manipulate_lines(window, cx, |lines| lines.sort())
 9904    }
 9905
 9906    pub fn sort_lines_case_insensitive(
 9907        &mut self,
 9908        _: &SortLinesCaseInsensitive,
 9909        window: &mut Window,
 9910        cx: &mut Context<Self>,
 9911    ) {
 9912        self.manipulate_lines(window, cx, |lines| {
 9913            lines.sort_by_key(|line| line.to_lowercase())
 9914        })
 9915    }
 9916
 9917    pub fn unique_lines_case_insensitive(
 9918        &mut self,
 9919        _: &UniqueLinesCaseInsensitive,
 9920        window: &mut Window,
 9921        cx: &mut Context<Self>,
 9922    ) {
 9923        self.manipulate_lines(window, cx, |lines| {
 9924            let mut seen = HashSet::default();
 9925            lines.retain(|line| seen.insert(line.to_lowercase()));
 9926        })
 9927    }
 9928
 9929    pub fn unique_lines_case_sensitive(
 9930        &mut self,
 9931        _: &UniqueLinesCaseSensitive,
 9932        window: &mut Window,
 9933        cx: &mut Context<Self>,
 9934    ) {
 9935        self.manipulate_lines(window, cx, |lines| {
 9936            let mut seen = HashSet::default();
 9937            lines.retain(|line| seen.insert(*line));
 9938        })
 9939    }
 9940
 9941    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9942        let Some(project) = self.project.clone() else {
 9943            return;
 9944        };
 9945        self.reload(project, window, cx)
 9946            .detach_and_notify_err(window, cx);
 9947    }
 9948
 9949    pub fn restore_file(
 9950        &mut self,
 9951        _: &::git::RestoreFile,
 9952        window: &mut Window,
 9953        cx: &mut Context<Self>,
 9954    ) {
 9955        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9956        let mut buffer_ids = HashSet::default();
 9957        let snapshot = self.buffer().read(cx).snapshot(cx);
 9958        for selection in self.selections.all::<usize>(cx) {
 9959            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9960        }
 9961
 9962        let buffer = self.buffer().read(cx);
 9963        let ranges = buffer_ids
 9964            .into_iter()
 9965            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9966            .collect::<Vec<_>>();
 9967
 9968        self.restore_hunks_in_ranges(ranges, window, cx);
 9969    }
 9970
 9971    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9972        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9973        let selections = self
 9974            .selections
 9975            .all(cx)
 9976            .into_iter()
 9977            .map(|s| s.range())
 9978            .collect();
 9979        self.restore_hunks_in_ranges(selections, window, cx);
 9980    }
 9981
 9982    pub fn restore_hunks_in_ranges(
 9983        &mut self,
 9984        ranges: Vec<Range<Point>>,
 9985        window: &mut Window,
 9986        cx: &mut Context<Editor>,
 9987    ) {
 9988        let mut revert_changes = HashMap::default();
 9989        let chunk_by = self
 9990            .snapshot(window, cx)
 9991            .hunks_for_ranges(ranges)
 9992            .into_iter()
 9993            .chunk_by(|hunk| hunk.buffer_id);
 9994        for (buffer_id, hunks) in &chunk_by {
 9995            let hunks = hunks.collect::<Vec<_>>();
 9996            for hunk in &hunks {
 9997                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9998            }
 9999            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10000        }
10001        drop(chunk_by);
10002        if !revert_changes.is_empty() {
10003            self.transact(window, cx, |editor, window, cx| {
10004                editor.restore(revert_changes, window, cx);
10005            });
10006        }
10007    }
10008
10009    pub fn open_active_item_in_terminal(
10010        &mut self,
10011        _: &OpenInTerminal,
10012        window: &mut Window,
10013        cx: &mut Context<Self>,
10014    ) {
10015        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10016            let project_path = buffer.read(cx).project_path(cx)?;
10017            let project = self.project.as_ref()?.read(cx);
10018            let entry = project.entry_for_path(&project_path, cx)?;
10019            let parent = match &entry.canonical_path {
10020                Some(canonical_path) => canonical_path.to_path_buf(),
10021                None => project.absolute_path(&project_path, cx)?,
10022            }
10023            .parent()?
10024            .to_path_buf();
10025            Some(parent)
10026        }) {
10027            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10028        }
10029    }
10030
10031    fn set_breakpoint_context_menu(
10032        &mut self,
10033        display_row: DisplayRow,
10034        position: Option<Anchor>,
10035        clicked_point: gpui::Point<Pixels>,
10036        window: &mut Window,
10037        cx: &mut Context<Self>,
10038    ) {
10039        if !cx.has_flag::<DebuggerFeatureFlag>() {
10040            return;
10041        }
10042        let source = self
10043            .buffer
10044            .read(cx)
10045            .snapshot(cx)
10046            .anchor_before(Point::new(display_row.0, 0u32));
10047
10048        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10049
10050        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10051            self,
10052            source,
10053            clicked_point,
10054            context_menu,
10055            window,
10056            cx,
10057        );
10058    }
10059
10060    fn add_edit_breakpoint_block(
10061        &mut self,
10062        anchor: Anchor,
10063        breakpoint: &Breakpoint,
10064        edit_action: BreakpointPromptEditAction,
10065        window: &mut Window,
10066        cx: &mut Context<Self>,
10067    ) {
10068        let weak_editor = cx.weak_entity();
10069        let bp_prompt = cx.new(|cx| {
10070            BreakpointPromptEditor::new(
10071                weak_editor,
10072                anchor,
10073                breakpoint.clone(),
10074                edit_action,
10075                window,
10076                cx,
10077            )
10078        });
10079
10080        let height = bp_prompt.update(cx, |this, cx| {
10081            this.prompt
10082                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10083        });
10084        let cloned_prompt = bp_prompt.clone();
10085        let blocks = vec![BlockProperties {
10086            style: BlockStyle::Sticky,
10087            placement: BlockPlacement::Above(anchor),
10088            height: Some(height),
10089            render: Arc::new(move |cx| {
10090                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10091                cloned_prompt.clone().into_any_element()
10092            }),
10093            priority: 0,
10094            render_in_minimap: true,
10095        }];
10096
10097        let focus_handle = bp_prompt.focus_handle(cx);
10098        window.focus(&focus_handle);
10099
10100        let block_ids = self.insert_blocks(blocks, None, cx);
10101        bp_prompt.update(cx, |prompt, _| {
10102            prompt.add_block_ids(block_ids);
10103        });
10104    }
10105
10106    pub(crate) fn breakpoint_at_row(
10107        &self,
10108        row: u32,
10109        window: &mut Window,
10110        cx: &mut Context<Self>,
10111    ) -> Option<(Anchor, Breakpoint)> {
10112        let snapshot = self.snapshot(window, cx);
10113        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10114
10115        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10116    }
10117
10118    pub(crate) fn breakpoint_at_anchor(
10119        &self,
10120        breakpoint_position: Anchor,
10121        snapshot: &EditorSnapshot,
10122        cx: &mut Context<Self>,
10123    ) -> Option<(Anchor, Breakpoint)> {
10124        let project = self.project.clone()?;
10125
10126        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10127            snapshot
10128                .buffer_snapshot
10129                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10130        })?;
10131
10132        let enclosing_excerpt = breakpoint_position.excerpt_id;
10133        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10134        let buffer_snapshot = buffer.read(cx).snapshot();
10135
10136        let row = buffer_snapshot
10137            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10138            .row;
10139
10140        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10141        let anchor_end = snapshot
10142            .buffer_snapshot
10143            .anchor_after(Point::new(row, line_len));
10144
10145        let bp = self
10146            .breakpoint_store
10147            .as_ref()?
10148            .read_with(cx, |breakpoint_store, cx| {
10149                breakpoint_store
10150                    .breakpoints(
10151                        &buffer,
10152                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10153                        &buffer_snapshot,
10154                        cx,
10155                    )
10156                    .next()
10157                    .and_then(|(bp, _)| {
10158                        let breakpoint_row = buffer_snapshot
10159                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10160                            .row;
10161
10162                        if breakpoint_row == row {
10163                            snapshot
10164                                .buffer_snapshot
10165                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10166                                .map(|position| (position, bp.bp.clone()))
10167                        } else {
10168                            None
10169                        }
10170                    })
10171            });
10172        bp
10173    }
10174
10175    pub fn edit_log_breakpoint(
10176        &mut self,
10177        _: &EditLogBreakpoint,
10178        window: &mut Window,
10179        cx: &mut Context<Self>,
10180    ) {
10181        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10182            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10183                message: None,
10184                state: BreakpointState::Enabled,
10185                condition: None,
10186                hit_condition: None,
10187            });
10188
10189            self.add_edit_breakpoint_block(
10190                anchor,
10191                &breakpoint,
10192                BreakpointPromptEditAction::Log,
10193                window,
10194                cx,
10195            );
10196        }
10197    }
10198
10199    fn breakpoints_at_cursors(
10200        &self,
10201        window: &mut Window,
10202        cx: &mut Context<Self>,
10203    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10204        let snapshot = self.snapshot(window, cx);
10205        let cursors = self
10206            .selections
10207            .disjoint_anchors()
10208            .into_iter()
10209            .map(|selection| {
10210                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10211
10212                let breakpoint_position = self
10213                    .breakpoint_at_row(cursor_position.row, window, cx)
10214                    .map(|bp| bp.0)
10215                    .unwrap_or_else(|| {
10216                        snapshot
10217                            .display_snapshot
10218                            .buffer_snapshot
10219                            .anchor_after(Point::new(cursor_position.row, 0))
10220                    });
10221
10222                let breakpoint = self
10223                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10224                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10225
10226                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10227            })
10228            // 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.
10229            .collect::<HashMap<Anchor, _>>();
10230
10231        cursors.into_iter().collect()
10232    }
10233
10234    pub fn enable_breakpoint(
10235        &mut self,
10236        _: &crate::actions::EnableBreakpoint,
10237        window: &mut Window,
10238        cx: &mut Context<Self>,
10239    ) {
10240        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10241            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10242                continue;
10243            };
10244            self.edit_breakpoint_at_anchor(
10245                anchor,
10246                breakpoint,
10247                BreakpointEditAction::InvertState,
10248                cx,
10249            );
10250        }
10251    }
10252
10253    pub fn disable_breakpoint(
10254        &mut self,
10255        _: &crate::actions::DisableBreakpoint,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) {
10259        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10260            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10261                continue;
10262            };
10263            self.edit_breakpoint_at_anchor(
10264                anchor,
10265                breakpoint,
10266                BreakpointEditAction::InvertState,
10267                cx,
10268            );
10269        }
10270    }
10271
10272    pub fn toggle_breakpoint(
10273        &mut self,
10274        _: &crate::actions::ToggleBreakpoint,
10275        window: &mut Window,
10276        cx: &mut Context<Self>,
10277    ) {
10278        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10279            if let Some(breakpoint) = breakpoint {
10280                self.edit_breakpoint_at_anchor(
10281                    anchor,
10282                    breakpoint,
10283                    BreakpointEditAction::Toggle,
10284                    cx,
10285                );
10286            } else {
10287                self.edit_breakpoint_at_anchor(
10288                    anchor,
10289                    Breakpoint::new_standard(),
10290                    BreakpointEditAction::Toggle,
10291                    cx,
10292                );
10293            }
10294        }
10295    }
10296
10297    pub fn edit_breakpoint_at_anchor(
10298        &mut self,
10299        breakpoint_position: Anchor,
10300        breakpoint: Breakpoint,
10301        edit_action: BreakpointEditAction,
10302        cx: &mut Context<Self>,
10303    ) {
10304        let Some(breakpoint_store) = &self.breakpoint_store else {
10305            return;
10306        };
10307
10308        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10309            if breakpoint_position == Anchor::min() {
10310                self.buffer()
10311                    .read(cx)
10312                    .excerpt_buffer_ids()
10313                    .into_iter()
10314                    .next()
10315            } else {
10316                None
10317            }
10318        }) else {
10319            return;
10320        };
10321
10322        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10323            return;
10324        };
10325
10326        breakpoint_store.update(cx, |breakpoint_store, cx| {
10327            breakpoint_store.toggle_breakpoint(
10328                buffer,
10329                BreakpointWithPosition {
10330                    position: breakpoint_position.text_anchor,
10331                    bp: breakpoint,
10332                },
10333                edit_action,
10334                cx,
10335            );
10336        });
10337
10338        cx.notify();
10339    }
10340
10341    #[cfg(any(test, feature = "test-support"))]
10342    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10343        self.breakpoint_store.clone()
10344    }
10345
10346    pub fn prepare_restore_change(
10347        &self,
10348        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10349        hunk: &MultiBufferDiffHunk,
10350        cx: &mut App,
10351    ) -> Option<()> {
10352        if hunk.is_created_file() {
10353            return None;
10354        }
10355        let buffer = self.buffer.read(cx);
10356        let diff = buffer.diff_for(hunk.buffer_id)?;
10357        let buffer = buffer.buffer(hunk.buffer_id)?;
10358        let buffer = buffer.read(cx);
10359        let original_text = diff
10360            .read(cx)
10361            .base_text()
10362            .as_rope()
10363            .slice(hunk.diff_base_byte_range.clone());
10364        let buffer_snapshot = buffer.snapshot();
10365        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10366        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10367            probe
10368                .0
10369                .start
10370                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10371                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10372        }) {
10373            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10374            Some(())
10375        } else {
10376            None
10377        }
10378    }
10379
10380    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10381        self.manipulate_lines(window, cx, |lines| lines.reverse())
10382    }
10383
10384    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10385        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10386    }
10387
10388    fn manipulate_lines<Fn>(
10389        &mut self,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392        mut callback: Fn,
10393    ) where
10394        Fn: FnMut(&mut Vec<&str>),
10395    {
10396        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10397
10398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10399        let buffer = self.buffer.read(cx).snapshot(cx);
10400
10401        let mut edits = Vec::new();
10402
10403        let selections = self.selections.all::<Point>(cx);
10404        let mut selections = selections.iter().peekable();
10405        let mut contiguous_row_selections = Vec::new();
10406        let mut new_selections = Vec::new();
10407        let mut added_lines = 0;
10408        let mut removed_lines = 0;
10409
10410        while let Some(selection) = selections.next() {
10411            let (start_row, end_row) = consume_contiguous_rows(
10412                &mut contiguous_row_selections,
10413                selection,
10414                &display_map,
10415                &mut selections,
10416            );
10417
10418            let start_point = Point::new(start_row.0, 0);
10419            let end_point = Point::new(
10420                end_row.previous_row().0,
10421                buffer.line_len(end_row.previous_row()),
10422            );
10423            let text = buffer
10424                .text_for_range(start_point..end_point)
10425                .collect::<String>();
10426
10427            let mut lines = text.split('\n').collect_vec();
10428
10429            let lines_before = lines.len();
10430            callback(&mut lines);
10431            let lines_after = lines.len();
10432
10433            edits.push((start_point..end_point, lines.join("\n")));
10434
10435            // Selections must change based on added and removed line count
10436            let start_row =
10437                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10438            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10439            new_selections.push(Selection {
10440                id: selection.id,
10441                start: start_row,
10442                end: end_row,
10443                goal: SelectionGoal::None,
10444                reversed: selection.reversed,
10445            });
10446
10447            if lines_after > lines_before {
10448                added_lines += lines_after - lines_before;
10449            } else if lines_before > lines_after {
10450                removed_lines += lines_before - lines_after;
10451            }
10452        }
10453
10454        self.transact(window, cx, |this, window, cx| {
10455            let buffer = this.buffer.update(cx, |buffer, cx| {
10456                buffer.edit(edits, None, cx);
10457                buffer.snapshot(cx)
10458            });
10459
10460            // Recalculate offsets on newly edited buffer
10461            let new_selections = new_selections
10462                .iter()
10463                .map(|s| {
10464                    let start_point = Point::new(s.start.0, 0);
10465                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10466                    Selection {
10467                        id: s.id,
10468                        start: buffer.point_to_offset(start_point),
10469                        end: buffer.point_to_offset(end_point),
10470                        goal: s.goal,
10471                        reversed: s.reversed,
10472                    }
10473                })
10474                .collect();
10475
10476            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10477                s.select(new_selections);
10478            });
10479
10480            this.request_autoscroll(Autoscroll::fit(), cx);
10481        });
10482    }
10483
10484    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10485        self.manipulate_text(window, cx, |text| {
10486            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10487            if has_upper_case_characters {
10488                text.to_lowercase()
10489            } else {
10490                text.to_uppercase()
10491            }
10492        })
10493    }
10494
10495    pub fn convert_to_upper_case(
10496        &mut self,
10497        _: &ConvertToUpperCase,
10498        window: &mut Window,
10499        cx: &mut Context<Self>,
10500    ) {
10501        self.manipulate_text(window, cx, |text| text.to_uppercase())
10502    }
10503
10504    pub fn convert_to_lower_case(
10505        &mut self,
10506        _: &ConvertToLowerCase,
10507        window: &mut Window,
10508        cx: &mut Context<Self>,
10509    ) {
10510        self.manipulate_text(window, cx, |text| text.to_lowercase())
10511    }
10512
10513    pub fn convert_to_title_case(
10514        &mut self,
10515        _: &ConvertToTitleCase,
10516        window: &mut Window,
10517        cx: &mut Context<Self>,
10518    ) {
10519        self.manipulate_text(window, cx, |text| {
10520            text.split('\n')
10521                .map(|line| line.to_case(Case::Title))
10522                .join("\n")
10523        })
10524    }
10525
10526    pub fn convert_to_snake_case(
10527        &mut self,
10528        _: &ConvertToSnakeCase,
10529        window: &mut Window,
10530        cx: &mut Context<Self>,
10531    ) {
10532        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10533    }
10534
10535    pub fn convert_to_kebab_case(
10536        &mut self,
10537        _: &ConvertToKebabCase,
10538        window: &mut Window,
10539        cx: &mut Context<Self>,
10540    ) {
10541        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10542    }
10543
10544    pub fn convert_to_upper_camel_case(
10545        &mut self,
10546        _: &ConvertToUpperCamelCase,
10547        window: &mut Window,
10548        cx: &mut Context<Self>,
10549    ) {
10550        self.manipulate_text(window, cx, |text| {
10551            text.split('\n')
10552                .map(|line| line.to_case(Case::UpperCamel))
10553                .join("\n")
10554        })
10555    }
10556
10557    pub fn convert_to_lower_camel_case(
10558        &mut self,
10559        _: &ConvertToLowerCamelCase,
10560        window: &mut Window,
10561        cx: &mut Context<Self>,
10562    ) {
10563        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10564    }
10565
10566    pub fn convert_to_opposite_case(
10567        &mut self,
10568        _: &ConvertToOppositeCase,
10569        window: &mut Window,
10570        cx: &mut Context<Self>,
10571    ) {
10572        self.manipulate_text(window, cx, |text| {
10573            text.chars()
10574                .fold(String::with_capacity(text.len()), |mut t, c| {
10575                    if c.is_uppercase() {
10576                        t.extend(c.to_lowercase());
10577                    } else {
10578                        t.extend(c.to_uppercase());
10579                    }
10580                    t
10581                })
10582        })
10583    }
10584
10585    pub fn convert_to_rot13(
10586        &mut self,
10587        _: &ConvertToRot13,
10588        window: &mut Window,
10589        cx: &mut Context<Self>,
10590    ) {
10591        self.manipulate_text(window, cx, |text| {
10592            text.chars()
10593                .map(|c| match c {
10594                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10595                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10596                    _ => c,
10597                })
10598                .collect()
10599        })
10600    }
10601
10602    pub fn convert_to_rot47(
10603        &mut self,
10604        _: &ConvertToRot47,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.manipulate_text(window, cx, |text| {
10609            text.chars()
10610                .map(|c| {
10611                    let code_point = c as u32;
10612                    if code_point >= 33 && code_point <= 126 {
10613                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10614                    }
10615                    c
10616                })
10617                .collect()
10618        })
10619    }
10620
10621    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10622    where
10623        Fn: FnMut(&str) -> String,
10624    {
10625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10626        let buffer = self.buffer.read(cx).snapshot(cx);
10627
10628        let mut new_selections = Vec::new();
10629        let mut edits = Vec::new();
10630        let mut selection_adjustment = 0i32;
10631
10632        for selection in self.selections.all::<usize>(cx) {
10633            let selection_is_empty = selection.is_empty();
10634
10635            let (start, end) = if selection_is_empty {
10636                let word_range = movement::surrounding_word(
10637                    &display_map,
10638                    selection.start.to_display_point(&display_map),
10639                );
10640                let start = word_range.start.to_offset(&display_map, Bias::Left);
10641                let end = word_range.end.to_offset(&display_map, Bias::Left);
10642                (start, end)
10643            } else {
10644                (selection.start, selection.end)
10645            };
10646
10647            let text = buffer.text_for_range(start..end).collect::<String>();
10648            let old_length = text.len() as i32;
10649            let text = callback(&text);
10650
10651            new_selections.push(Selection {
10652                start: (start as i32 - selection_adjustment) as usize,
10653                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10654                goal: SelectionGoal::None,
10655                ..selection
10656            });
10657
10658            selection_adjustment += old_length - text.len() as i32;
10659
10660            edits.push((start..end, text));
10661        }
10662
10663        self.transact(window, cx, |this, window, cx| {
10664            this.buffer.update(cx, |buffer, cx| {
10665                buffer.edit(edits, None, cx);
10666            });
10667
10668            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10669                s.select(new_selections);
10670            });
10671
10672            this.request_autoscroll(Autoscroll::fit(), cx);
10673        });
10674    }
10675
10676    pub fn move_selection_on_drop(
10677        &mut self,
10678        selection: &Selection<Anchor>,
10679        target: DisplayPoint,
10680        is_cut: bool,
10681        window: &mut Window,
10682        cx: &mut Context<Self>,
10683    ) {
10684        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10685        let buffer = &display_map.buffer_snapshot;
10686        let mut edits = Vec::new();
10687        let insert_point = display_map
10688            .clip_point(target, Bias::Left)
10689            .to_point(&display_map);
10690        let text = buffer
10691            .text_for_range(selection.start..selection.end)
10692            .collect::<String>();
10693        if is_cut {
10694            edits.push(((selection.start..selection.end), String::new()));
10695        }
10696        let insert_anchor = buffer.anchor_before(insert_point);
10697        edits.push(((insert_anchor..insert_anchor), text));
10698        let last_edit_start = insert_anchor.bias_left(buffer);
10699        let last_edit_end = insert_anchor.bias_right(buffer);
10700        self.transact(window, cx, |this, window, cx| {
10701            this.buffer.update(cx, |buffer, cx| {
10702                buffer.edit(edits, None, cx);
10703            });
10704            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10705                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10706            });
10707        });
10708    }
10709
10710    pub fn clear_selection_drag_state(&mut self) {
10711        self.selection_drag_state = SelectionDragState::None;
10712    }
10713
10714    pub fn duplicate(
10715        &mut self,
10716        upwards: bool,
10717        whole_lines: bool,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10722
10723        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10724        let buffer = &display_map.buffer_snapshot;
10725        let selections = self.selections.all::<Point>(cx);
10726
10727        let mut edits = Vec::new();
10728        let mut selections_iter = selections.iter().peekable();
10729        while let Some(selection) = selections_iter.next() {
10730            let mut rows = selection.spanned_rows(false, &display_map);
10731            // duplicate line-wise
10732            if whole_lines || selection.start == selection.end {
10733                // Avoid duplicating the same lines twice.
10734                while let Some(next_selection) = selections_iter.peek() {
10735                    let next_rows = next_selection.spanned_rows(false, &display_map);
10736                    if next_rows.start < rows.end {
10737                        rows.end = next_rows.end;
10738                        selections_iter.next().unwrap();
10739                    } else {
10740                        break;
10741                    }
10742                }
10743
10744                // Copy the text from the selected row region and splice it either at the start
10745                // or end of the region.
10746                let start = Point::new(rows.start.0, 0);
10747                let end = Point::new(
10748                    rows.end.previous_row().0,
10749                    buffer.line_len(rows.end.previous_row()),
10750                );
10751                let text = buffer
10752                    .text_for_range(start..end)
10753                    .chain(Some("\n"))
10754                    .collect::<String>();
10755                let insert_location = if upwards {
10756                    Point::new(rows.end.0, 0)
10757                } else {
10758                    start
10759                };
10760                edits.push((insert_location..insert_location, text));
10761            } else {
10762                // duplicate character-wise
10763                let start = selection.start;
10764                let end = selection.end;
10765                let text = buffer.text_for_range(start..end).collect::<String>();
10766                edits.push((selection.end..selection.end, text));
10767            }
10768        }
10769
10770        self.transact(window, cx, |this, _, cx| {
10771            this.buffer.update(cx, |buffer, cx| {
10772                buffer.edit(edits, None, cx);
10773            });
10774
10775            this.request_autoscroll(Autoscroll::fit(), cx);
10776        });
10777    }
10778
10779    pub fn duplicate_line_up(
10780        &mut self,
10781        _: &DuplicateLineUp,
10782        window: &mut Window,
10783        cx: &mut Context<Self>,
10784    ) {
10785        self.duplicate(true, true, window, cx);
10786    }
10787
10788    pub fn duplicate_line_down(
10789        &mut self,
10790        _: &DuplicateLineDown,
10791        window: &mut Window,
10792        cx: &mut Context<Self>,
10793    ) {
10794        self.duplicate(false, true, window, cx);
10795    }
10796
10797    pub fn duplicate_selection(
10798        &mut self,
10799        _: &DuplicateSelection,
10800        window: &mut Window,
10801        cx: &mut Context<Self>,
10802    ) {
10803        self.duplicate(false, false, window, cx);
10804    }
10805
10806    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10807        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10808
10809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10810        let buffer = self.buffer.read(cx).snapshot(cx);
10811
10812        let mut edits = Vec::new();
10813        let mut unfold_ranges = Vec::new();
10814        let mut refold_creases = Vec::new();
10815
10816        let selections = self.selections.all::<Point>(cx);
10817        let mut selections = selections.iter().peekable();
10818        let mut contiguous_row_selections = Vec::new();
10819        let mut new_selections = Vec::new();
10820
10821        while let Some(selection) = selections.next() {
10822            // Find all the selections that span a contiguous row range
10823            let (start_row, end_row) = consume_contiguous_rows(
10824                &mut contiguous_row_selections,
10825                selection,
10826                &display_map,
10827                &mut selections,
10828            );
10829
10830            // Move the text spanned by the row range to be before the line preceding the row range
10831            if start_row.0 > 0 {
10832                let range_to_move = Point::new(
10833                    start_row.previous_row().0,
10834                    buffer.line_len(start_row.previous_row()),
10835                )
10836                    ..Point::new(
10837                        end_row.previous_row().0,
10838                        buffer.line_len(end_row.previous_row()),
10839                    );
10840                let insertion_point = display_map
10841                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10842                    .0;
10843
10844                // Don't move lines across excerpts
10845                if buffer
10846                    .excerpt_containing(insertion_point..range_to_move.end)
10847                    .is_some()
10848                {
10849                    let text = buffer
10850                        .text_for_range(range_to_move.clone())
10851                        .flat_map(|s| s.chars())
10852                        .skip(1)
10853                        .chain(['\n'])
10854                        .collect::<String>();
10855
10856                    edits.push((
10857                        buffer.anchor_after(range_to_move.start)
10858                            ..buffer.anchor_before(range_to_move.end),
10859                        String::new(),
10860                    ));
10861                    let insertion_anchor = buffer.anchor_after(insertion_point);
10862                    edits.push((insertion_anchor..insertion_anchor, text));
10863
10864                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10865
10866                    // Move selections up
10867                    new_selections.extend(contiguous_row_selections.drain(..).map(
10868                        |mut selection| {
10869                            selection.start.row -= row_delta;
10870                            selection.end.row -= row_delta;
10871                            selection
10872                        },
10873                    ));
10874
10875                    // Move folds up
10876                    unfold_ranges.push(range_to_move.clone());
10877                    for fold in display_map.folds_in_range(
10878                        buffer.anchor_before(range_to_move.start)
10879                            ..buffer.anchor_after(range_to_move.end),
10880                    ) {
10881                        let mut start = fold.range.start.to_point(&buffer);
10882                        let mut end = fold.range.end.to_point(&buffer);
10883                        start.row -= row_delta;
10884                        end.row -= row_delta;
10885                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10886                    }
10887                }
10888            }
10889
10890            // If we didn't move line(s), preserve the existing selections
10891            new_selections.append(&mut contiguous_row_selections);
10892        }
10893
10894        self.transact(window, cx, |this, window, cx| {
10895            this.unfold_ranges(&unfold_ranges, true, true, cx);
10896            this.buffer.update(cx, |buffer, cx| {
10897                for (range, text) in edits {
10898                    buffer.edit([(range, text)], None, cx);
10899                }
10900            });
10901            this.fold_creases(refold_creases, true, window, cx);
10902            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10903                s.select(new_selections);
10904            })
10905        });
10906    }
10907
10908    pub fn move_line_down(
10909        &mut self,
10910        _: &MoveLineDown,
10911        window: &mut Window,
10912        cx: &mut Context<Self>,
10913    ) {
10914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10915
10916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10917        let buffer = self.buffer.read(cx).snapshot(cx);
10918
10919        let mut edits = Vec::new();
10920        let mut unfold_ranges = Vec::new();
10921        let mut refold_creases = Vec::new();
10922
10923        let selections = self.selections.all::<Point>(cx);
10924        let mut selections = selections.iter().peekable();
10925        let mut contiguous_row_selections = Vec::new();
10926        let mut new_selections = Vec::new();
10927
10928        while let Some(selection) = selections.next() {
10929            // Find all the selections that span a contiguous row range
10930            let (start_row, end_row) = consume_contiguous_rows(
10931                &mut contiguous_row_selections,
10932                selection,
10933                &display_map,
10934                &mut selections,
10935            );
10936
10937            // Move the text spanned by the row range to be after the last line of the row range
10938            if end_row.0 <= buffer.max_point().row {
10939                let range_to_move =
10940                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10941                let insertion_point = display_map
10942                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10943                    .0;
10944
10945                // Don't move lines across excerpt boundaries
10946                if buffer
10947                    .excerpt_containing(range_to_move.start..insertion_point)
10948                    .is_some()
10949                {
10950                    let mut text = String::from("\n");
10951                    text.extend(buffer.text_for_range(range_to_move.clone()));
10952                    text.pop(); // Drop trailing newline
10953                    edits.push((
10954                        buffer.anchor_after(range_to_move.start)
10955                            ..buffer.anchor_before(range_to_move.end),
10956                        String::new(),
10957                    ));
10958                    let insertion_anchor = buffer.anchor_after(insertion_point);
10959                    edits.push((insertion_anchor..insertion_anchor, text));
10960
10961                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10962
10963                    // Move selections down
10964                    new_selections.extend(contiguous_row_selections.drain(..).map(
10965                        |mut selection| {
10966                            selection.start.row += row_delta;
10967                            selection.end.row += row_delta;
10968                            selection
10969                        },
10970                    ));
10971
10972                    // Move folds down
10973                    unfold_ranges.push(range_to_move.clone());
10974                    for fold in display_map.folds_in_range(
10975                        buffer.anchor_before(range_to_move.start)
10976                            ..buffer.anchor_after(range_to_move.end),
10977                    ) {
10978                        let mut start = fold.range.start.to_point(&buffer);
10979                        let mut end = fold.range.end.to_point(&buffer);
10980                        start.row += row_delta;
10981                        end.row += row_delta;
10982                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10983                    }
10984                }
10985            }
10986
10987            // If we didn't move line(s), preserve the existing selections
10988            new_selections.append(&mut contiguous_row_selections);
10989        }
10990
10991        self.transact(window, cx, |this, window, cx| {
10992            this.unfold_ranges(&unfold_ranges, true, true, cx);
10993            this.buffer.update(cx, |buffer, cx| {
10994                for (range, text) in edits {
10995                    buffer.edit([(range, text)], None, cx);
10996                }
10997            });
10998            this.fold_creases(refold_creases, true, window, cx);
10999            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11000                s.select(new_selections)
11001            });
11002        });
11003    }
11004
11005    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11006        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11007        let text_layout_details = &self.text_layout_details(window);
11008        self.transact(window, cx, |this, window, cx| {
11009            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11010                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11011                s.move_with(|display_map, selection| {
11012                    if !selection.is_empty() {
11013                        return;
11014                    }
11015
11016                    let mut head = selection.head();
11017                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11018                    if head.column() == display_map.line_len(head.row()) {
11019                        transpose_offset = display_map
11020                            .buffer_snapshot
11021                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11022                    }
11023
11024                    if transpose_offset == 0 {
11025                        return;
11026                    }
11027
11028                    *head.column_mut() += 1;
11029                    head = display_map.clip_point(head, Bias::Right);
11030                    let goal = SelectionGoal::HorizontalPosition(
11031                        display_map
11032                            .x_for_display_point(head, text_layout_details)
11033                            .into(),
11034                    );
11035                    selection.collapse_to(head, goal);
11036
11037                    let transpose_start = display_map
11038                        .buffer_snapshot
11039                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11040                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11041                        let transpose_end = display_map
11042                            .buffer_snapshot
11043                            .clip_offset(transpose_offset + 1, Bias::Right);
11044                        if let Some(ch) =
11045                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11046                        {
11047                            edits.push((transpose_start..transpose_offset, String::new()));
11048                            edits.push((transpose_end..transpose_end, ch.to_string()));
11049                        }
11050                    }
11051                });
11052                edits
11053            });
11054            this.buffer
11055                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11056            let selections = this.selections.all::<usize>(cx);
11057            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11058                s.select(selections);
11059            });
11060        });
11061    }
11062
11063    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11064        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11065        self.rewrap_impl(RewrapOptions::default(), cx)
11066    }
11067
11068    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11069        let buffer = self.buffer.read(cx).snapshot(cx);
11070        let selections = self.selections.all::<Point>(cx);
11071
11072        // Shrink and split selections to respect paragraph boundaries.
11073        let ranges = selections.into_iter().flat_map(|selection| {
11074            let language_settings = buffer.language_settings_at(selection.head(), cx);
11075            let language_scope = buffer.language_scope_at(selection.head());
11076
11077            let Some(start_row) = (selection.start.row..=selection.end.row)
11078                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11079            else {
11080                return vec![];
11081            };
11082            let Some(end_row) = (selection.start.row..=selection.end.row)
11083                .rev()
11084                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11085            else {
11086                return vec![];
11087            };
11088
11089            let mut row = start_row;
11090            let mut ranges = Vec::new();
11091            while let Some(blank_row) =
11092                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11093            {
11094                let next_paragraph_start = (blank_row + 1..=end_row)
11095                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11096                    .unwrap();
11097                ranges.push((
11098                    language_settings.clone(),
11099                    language_scope.clone(),
11100                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11101                ));
11102                row = next_paragraph_start;
11103            }
11104            ranges.push((
11105                language_settings.clone(),
11106                language_scope.clone(),
11107                Point::new(row, 0)..Point::new(end_row, 0),
11108            ));
11109
11110            ranges
11111        });
11112
11113        let mut edits = Vec::new();
11114        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11115
11116        for (language_settings, language_scope, range) in ranges {
11117            let mut start_row = range.start.row;
11118            let mut end_row = range.end.row;
11119
11120            // Skip selections that overlap with a range that has already been rewrapped.
11121            let selection_range = start_row..end_row;
11122            if rewrapped_row_ranges
11123                .iter()
11124                .any(|range| range.overlaps(&selection_range))
11125            {
11126                continue;
11127            }
11128
11129            let tab_size = language_settings.tab_size;
11130
11131            // Since not all lines in the selection may be at the same indent
11132            // level, choose the indent size that is the most common between all
11133            // of the lines.
11134            //
11135            // If there is a tie, we use the deepest indent.
11136            let (indent_size, indent_end) = {
11137                let mut indent_size_occurrences = HashMap::default();
11138                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11139
11140                for row in start_row..=end_row {
11141                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11142                    rows_by_indent_size.entry(indent).or_default().push(row);
11143                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11144                }
11145
11146                let indent_size = indent_size_occurrences
11147                    .into_iter()
11148                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11149                    .map(|(indent, _)| indent)
11150                    .unwrap_or_default();
11151                let row = rows_by_indent_size[&indent_size][0];
11152                let indent_end = Point::new(row, indent_size.len);
11153
11154                (indent_size, indent_end)
11155            };
11156
11157            let mut line_prefix = indent_size.chars().collect::<String>();
11158
11159            let mut inside_comment = false;
11160            if let Some(comment_prefix) = language_scope.and_then(|language| {
11161                language
11162                    .line_comment_prefixes()
11163                    .iter()
11164                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11165                    .cloned()
11166            }) {
11167                line_prefix.push_str(&comment_prefix);
11168                inside_comment = true;
11169            }
11170
11171            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11172                RewrapBehavior::InComments => inside_comment,
11173                RewrapBehavior::InSelections => !range.is_empty(),
11174                RewrapBehavior::Anywhere => true,
11175            };
11176
11177            let should_rewrap = options.override_language_settings
11178                || allow_rewrap_based_on_language
11179                || self.hard_wrap.is_some();
11180            if !should_rewrap {
11181                continue;
11182            }
11183
11184            if range.is_empty() {
11185                'expand_upwards: while start_row > 0 {
11186                    let prev_row = start_row - 1;
11187                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11188                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11189                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11190                    {
11191                        start_row = prev_row;
11192                    } else {
11193                        break 'expand_upwards;
11194                    }
11195                }
11196
11197                'expand_downwards: while end_row < buffer.max_point().row {
11198                    let next_row = end_row + 1;
11199                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11200                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11201                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11202                    {
11203                        end_row = next_row;
11204                    } else {
11205                        break 'expand_downwards;
11206                    }
11207                }
11208            }
11209
11210            let start = Point::new(start_row, 0);
11211            let start_offset = start.to_offset(&buffer);
11212            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11213            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11214            let Some(lines_without_prefixes) = selection_text
11215                .lines()
11216                .map(|line| {
11217                    line.strip_prefix(&line_prefix)
11218                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11219                        .with_context(|| {
11220                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11221                        })
11222                })
11223                .collect::<Result<Vec<_>, _>>()
11224                .log_err()
11225            else {
11226                continue;
11227            };
11228
11229            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11230                buffer
11231                    .language_settings_at(Point::new(start_row, 0), cx)
11232                    .preferred_line_length as usize
11233            });
11234            let wrapped_text = wrap_with_prefix(
11235                line_prefix,
11236                lines_without_prefixes.join("\n"),
11237                wrap_column,
11238                tab_size,
11239                options.preserve_existing_whitespace,
11240            );
11241
11242            // TODO: should always use char-based diff while still supporting cursor behavior that
11243            // matches vim.
11244            let mut diff_options = DiffOptions::default();
11245            if options.override_language_settings {
11246                diff_options.max_word_diff_len = 0;
11247                diff_options.max_word_diff_line_count = 0;
11248            } else {
11249                diff_options.max_word_diff_len = usize::MAX;
11250                diff_options.max_word_diff_line_count = usize::MAX;
11251            }
11252
11253            for (old_range, new_text) in
11254                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11255            {
11256                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11257                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11258                edits.push((edit_start..edit_end, new_text));
11259            }
11260
11261            rewrapped_row_ranges.push(start_row..=end_row);
11262        }
11263
11264        self.buffer
11265            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11266    }
11267
11268    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11269        let mut text = String::new();
11270        let buffer = self.buffer.read(cx).snapshot(cx);
11271        let mut selections = self.selections.all::<Point>(cx);
11272        let mut clipboard_selections = Vec::with_capacity(selections.len());
11273        {
11274            let max_point = buffer.max_point();
11275            let mut is_first = true;
11276            for selection in &mut selections {
11277                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11278                if is_entire_line {
11279                    selection.start = Point::new(selection.start.row, 0);
11280                    if !selection.is_empty() && selection.end.column == 0 {
11281                        selection.end = cmp::min(max_point, selection.end);
11282                    } else {
11283                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11284                    }
11285                    selection.goal = SelectionGoal::None;
11286                }
11287                if is_first {
11288                    is_first = false;
11289                } else {
11290                    text += "\n";
11291                }
11292                let mut len = 0;
11293                for chunk in buffer.text_for_range(selection.start..selection.end) {
11294                    text.push_str(chunk);
11295                    len += chunk.len();
11296                }
11297                clipboard_selections.push(ClipboardSelection {
11298                    len,
11299                    is_entire_line,
11300                    first_line_indent: buffer
11301                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11302                        .len,
11303                });
11304            }
11305        }
11306
11307        self.transact(window, cx, |this, window, cx| {
11308            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11309                s.select(selections);
11310            });
11311            this.insert("", window, cx);
11312        });
11313        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11314    }
11315
11316    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11317        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11318        let item = self.cut_common(window, cx);
11319        cx.write_to_clipboard(item);
11320    }
11321
11322    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11323        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11324        self.change_selections(None, window, cx, |s| {
11325            s.move_with(|snapshot, sel| {
11326                if sel.is_empty() {
11327                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11328                }
11329            });
11330        });
11331        let item = self.cut_common(window, cx);
11332        cx.set_global(KillRing(item))
11333    }
11334
11335    pub fn kill_ring_yank(
11336        &mut self,
11337        _: &KillRingYank,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11342        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11343            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11344                (kill_ring.text().to_string(), kill_ring.metadata_json())
11345            } else {
11346                return;
11347            }
11348        } else {
11349            return;
11350        };
11351        self.do_paste(&text, metadata, false, window, cx);
11352    }
11353
11354    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11355        self.do_copy(true, cx);
11356    }
11357
11358    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11359        self.do_copy(false, cx);
11360    }
11361
11362    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11363        let selections = self.selections.all::<Point>(cx);
11364        let buffer = self.buffer.read(cx).read(cx);
11365        let mut text = String::new();
11366
11367        let mut clipboard_selections = Vec::with_capacity(selections.len());
11368        {
11369            let max_point = buffer.max_point();
11370            let mut is_first = true;
11371            for selection in &selections {
11372                let mut start = selection.start;
11373                let mut end = selection.end;
11374                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11375                if is_entire_line {
11376                    start = Point::new(start.row, 0);
11377                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11378                }
11379
11380                let mut trimmed_selections = Vec::new();
11381                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11382                    let row = MultiBufferRow(start.row);
11383                    let first_indent = buffer.indent_size_for_line(row);
11384                    if first_indent.len == 0 || start.column > first_indent.len {
11385                        trimmed_selections.push(start..end);
11386                    } else {
11387                        trimmed_selections.push(
11388                            Point::new(row.0, first_indent.len)
11389                                ..Point::new(row.0, buffer.line_len(row)),
11390                        );
11391                        for row in start.row + 1..=end.row {
11392                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11393                            if row == end.row {
11394                                line_len = end.column;
11395                            }
11396                            if line_len == 0 {
11397                                trimmed_selections
11398                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11399                                continue;
11400                            }
11401                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11402                            if row_indent_size.len >= first_indent.len {
11403                                trimmed_selections.push(
11404                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11405                                );
11406                            } else {
11407                                trimmed_selections.clear();
11408                                trimmed_selections.push(start..end);
11409                                break;
11410                            }
11411                        }
11412                    }
11413                } else {
11414                    trimmed_selections.push(start..end);
11415                }
11416
11417                for trimmed_range in trimmed_selections {
11418                    if is_first {
11419                        is_first = false;
11420                    } else {
11421                        text += "\n";
11422                    }
11423                    let mut len = 0;
11424                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11425                        text.push_str(chunk);
11426                        len += chunk.len();
11427                    }
11428                    clipboard_selections.push(ClipboardSelection {
11429                        len,
11430                        is_entire_line,
11431                        first_line_indent: buffer
11432                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11433                            .len,
11434                    });
11435                }
11436            }
11437        }
11438
11439        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11440            text,
11441            clipboard_selections,
11442        ));
11443    }
11444
11445    pub fn do_paste(
11446        &mut self,
11447        text: &String,
11448        clipboard_selections: Option<Vec<ClipboardSelection>>,
11449        handle_entire_lines: bool,
11450        window: &mut Window,
11451        cx: &mut Context<Self>,
11452    ) {
11453        if self.read_only(cx) {
11454            return;
11455        }
11456
11457        let clipboard_text = Cow::Borrowed(text);
11458
11459        self.transact(window, cx, |this, window, cx| {
11460            if let Some(mut clipboard_selections) = clipboard_selections {
11461                let old_selections = this.selections.all::<usize>(cx);
11462                let all_selections_were_entire_line =
11463                    clipboard_selections.iter().all(|s| s.is_entire_line);
11464                let first_selection_indent_column =
11465                    clipboard_selections.first().map(|s| s.first_line_indent);
11466                if clipboard_selections.len() != old_selections.len() {
11467                    clipboard_selections.drain(..);
11468                }
11469                let cursor_offset = this.selections.last::<usize>(cx).head();
11470                let mut auto_indent_on_paste = true;
11471
11472                this.buffer.update(cx, |buffer, cx| {
11473                    let snapshot = buffer.read(cx);
11474                    auto_indent_on_paste = snapshot
11475                        .language_settings_at(cursor_offset, cx)
11476                        .auto_indent_on_paste;
11477
11478                    let mut start_offset = 0;
11479                    let mut edits = Vec::new();
11480                    let mut original_indent_columns = Vec::new();
11481                    for (ix, selection) in old_selections.iter().enumerate() {
11482                        let to_insert;
11483                        let entire_line;
11484                        let original_indent_column;
11485                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11486                            let end_offset = start_offset + clipboard_selection.len;
11487                            to_insert = &clipboard_text[start_offset..end_offset];
11488                            entire_line = clipboard_selection.is_entire_line;
11489                            start_offset = end_offset + 1;
11490                            original_indent_column = Some(clipboard_selection.first_line_indent);
11491                        } else {
11492                            to_insert = clipboard_text.as_str();
11493                            entire_line = all_selections_were_entire_line;
11494                            original_indent_column = first_selection_indent_column
11495                        }
11496
11497                        // If the corresponding selection was empty when this slice of the
11498                        // clipboard text was written, then the entire line containing the
11499                        // selection was copied. If this selection is also currently empty,
11500                        // then paste the line before the current line of the buffer.
11501                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11502                            let column = selection.start.to_point(&snapshot).column as usize;
11503                            let line_start = selection.start - column;
11504                            line_start..line_start
11505                        } else {
11506                            selection.range()
11507                        };
11508
11509                        edits.push((range, to_insert));
11510                        original_indent_columns.push(original_indent_column);
11511                    }
11512                    drop(snapshot);
11513
11514                    buffer.edit(
11515                        edits,
11516                        if auto_indent_on_paste {
11517                            Some(AutoindentMode::Block {
11518                                original_indent_columns,
11519                            })
11520                        } else {
11521                            None
11522                        },
11523                        cx,
11524                    );
11525                });
11526
11527                let selections = this.selections.all::<usize>(cx);
11528                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11529                    s.select(selections)
11530                });
11531            } else {
11532                this.insert(&clipboard_text, window, cx);
11533            }
11534        });
11535    }
11536
11537    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11538        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11539        if let Some(item) = cx.read_from_clipboard() {
11540            let entries = item.entries();
11541
11542            match entries.first() {
11543                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11544                // of all the pasted entries.
11545                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11546                    .do_paste(
11547                        clipboard_string.text(),
11548                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11549                        true,
11550                        window,
11551                        cx,
11552                    ),
11553                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11554            }
11555        }
11556    }
11557
11558    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11559        if self.read_only(cx) {
11560            return;
11561        }
11562
11563        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11564
11565        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11566            if let Some((selections, _)) =
11567                self.selection_history.transaction(transaction_id).cloned()
11568            {
11569                self.change_selections(None, window, cx, |s| {
11570                    s.select_anchors(selections.to_vec());
11571                });
11572            } else {
11573                log::error!(
11574                    "No entry in selection_history found for undo. \
11575                     This may correspond to a bug where undo does not update the selection. \
11576                     If this is occurring, please add details to \
11577                     https://github.com/zed-industries/zed/issues/22692"
11578                );
11579            }
11580            self.request_autoscroll(Autoscroll::fit(), cx);
11581            self.unmark_text(window, cx);
11582            self.refresh_inline_completion(true, false, window, cx);
11583            cx.emit(EditorEvent::Edited { transaction_id });
11584            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11585        }
11586    }
11587
11588    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11589        if self.read_only(cx) {
11590            return;
11591        }
11592
11593        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11594
11595        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11596            if let Some((_, Some(selections))) =
11597                self.selection_history.transaction(transaction_id).cloned()
11598            {
11599                self.change_selections(None, window, cx, |s| {
11600                    s.select_anchors(selections.to_vec());
11601                });
11602            } else {
11603                log::error!(
11604                    "No entry in selection_history found for redo. \
11605                     This may correspond to a bug where undo does not update the selection. \
11606                     If this is occurring, please add details to \
11607                     https://github.com/zed-industries/zed/issues/22692"
11608                );
11609            }
11610            self.request_autoscroll(Autoscroll::fit(), cx);
11611            self.unmark_text(window, cx);
11612            self.refresh_inline_completion(true, false, window, cx);
11613            cx.emit(EditorEvent::Edited { transaction_id });
11614        }
11615    }
11616
11617    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11618        self.buffer
11619            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11620    }
11621
11622    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11623        self.buffer
11624            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11625    }
11626
11627    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11628        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11629        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11630            s.move_with(|map, selection| {
11631                let cursor = if selection.is_empty() {
11632                    movement::left(map, selection.start)
11633                } else {
11634                    selection.start
11635                };
11636                selection.collapse_to(cursor, SelectionGoal::None);
11637            });
11638        })
11639    }
11640
11641    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11642        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11643        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11645        })
11646    }
11647
11648    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11649        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11650        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11651            s.move_with(|map, selection| {
11652                let cursor = if selection.is_empty() {
11653                    movement::right(map, selection.end)
11654                } else {
11655                    selection.end
11656                };
11657                selection.collapse_to(cursor, SelectionGoal::None)
11658            });
11659        })
11660    }
11661
11662    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11663        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11664        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11665            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11666        })
11667    }
11668
11669    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11670        if self.take_rename(true, window, cx).is_some() {
11671            return;
11672        }
11673
11674        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11675            cx.propagate();
11676            return;
11677        }
11678
11679        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11680
11681        let text_layout_details = &self.text_layout_details(window);
11682        let selection_count = self.selections.count();
11683        let first_selection = self.selections.first_anchor();
11684
11685        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11686            s.move_with(|map, selection| {
11687                if !selection.is_empty() {
11688                    selection.goal = SelectionGoal::None;
11689                }
11690                let (cursor, goal) = movement::up(
11691                    map,
11692                    selection.start,
11693                    selection.goal,
11694                    false,
11695                    text_layout_details,
11696                );
11697                selection.collapse_to(cursor, goal);
11698            });
11699        });
11700
11701        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11702        {
11703            cx.propagate();
11704        }
11705    }
11706
11707    pub fn move_up_by_lines(
11708        &mut self,
11709        action: &MoveUpByLines,
11710        window: &mut Window,
11711        cx: &mut Context<Self>,
11712    ) {
11713        if self.take_rename(true, window, cx).is_some() {
11714            return;
11715        }
11716
11717        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11718            cx.propagate();
11719            return;
11720        }
11721
11722        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11723
11724        let text_layout_details = &self.text_layout_details(window);
11725
11726        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11727            s.move_with(|map, selection| {
11728                if !selection.is_empty() {
11729                    selection.goal = SelectionGoal::None;
11730                }
11731                let (cursor, goal) = movement::up_by_rows(
11732                    map,
11733                    selection.start,
11734                    action.lines,
11735                    selection.goal,
11736                    false,
11737                    text_layout_details,
11738                );
11739                selection.collapse_to(cursor, goal);
11740            });
11741        })
11742    }
11743
11744    pub fn move_down_by_lines(
11745        &mut self,
11746        action: &MoveDownByLines,
11747        window: &mut Window,
11748        cx: &mut Context<Self>,
11749    ) {
11750        if self.take_rename(true, window, cx).is_some() {
11751            return;
11752        }
11753
11754        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11755            cx.propagate();
11756            return;
11757        }
11758
11759        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11760
11761        let text_layout_details = &self.text_layout_details(window);
11762
11763        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11764            s.move_with(|map, selection| {
11765                if !selection.is_empty() {
11766                    selection.goal = SelectionGoal::None;
11767                }
11768                let (cursor, goal) = movement::down_by_rows(
11769                    map,
11770                    selection.start,
11771                    action.lines,
11772                    selection.goal,
11773                    false,
11774                    text_layout_details,
11775                );
11776                selection.collapse_to(cursor, goal);
11777            });
11778        })
11779    }
11780
11781    pub fn select_down_by_lines(
11782        &mut self,
11783        action: &SelectDownByLines,
11784        window: &mut Window,
11785        cx: &mut Context<Self>,
11786    ) {
11787        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11788        let text_layout_details = &self.text_layout_details(window);
11789        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11790            s.move_heads_with(|map, head, goal| {
11791                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11792            })
11793        })
11794    }
11795
11796    pub fn select_up_by_lines(
11797        &mut self,
11798        action: &SelectUpByLines,
11799        window: &mut Window,
11800        cx: &mut Context<Self>,
11801    ) {
11802        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11803        let text_layout_details = &self.text_layout_details(window);
11804        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11805            s.move_heads_with(|map, head, goal| {
11806                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11807            })
11808        })
11809    }
11810
11811    pub fn select_page_up(
11812        &mut self,
11813        _: &SelectPageUp,
11814        window: &mut Window,
11815        cx: &mut Context<Self>,
11816    ) {
11817        let Some(row_count) = self.visible_row_count() else {
11818            return;
11819        };
11820
11821        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11822
11823        let text_layout_details = &self.text_layout_details(window);
11824
11825        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11826            s.move_heads_with(|map, head, goal| {
11827                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11828            })
11829        })
11830    }
11831
11832    pub fn move_page_up(
11833        &mut self,
11834        action: &MovePageUp,
11835        window: &mut Window,
11836        cx: &mut Context<Self>,
11837    ) {
11838        if self.take_rename(true, window, cx).is_some() {
11839            return;
11840        }
11841
11842        if self
11843            .context_menu
11844            .borrow_mut()
11845            .as_mut()
11846            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11847            .unwrap_or(false)
11848        {
11849            return;
11850        }
11851
11852        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11853            cx.propagate();
11854            return;
11855        }
11856
11857        let Some(row_count) = self.visible_row_count() else {
11858            return;
11859        };
11860
11861        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11862
11863        let autoscroll = if action.center_cursor {
11864            Autoscroll::center()
11865        } else {
11866            Autoscroll::fit()
11867        };
11868
11869        let text_layout_details = &self.text_layout_details(window);
11870
11871        self.change_selections(Some(autoscroll), window, cx, |s| {
11872            s.move_with(|map, selection| {
11873                if !selection.is_empty() {
11874                    selection.goal = SelectionGoal::None;
11875                }
11876                let (cursor, goal) = movement::up_by_rows(
11877                    map,
11878                    selection.end,
11879                    row_count,
11880                    selection.goal,
11881                    false,
11882                    text_layout_details,
11883                );
11884                selection.collapse_to(cursor, goal);
11885            });
11886        });
11887    }
11888
11889    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11890        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11891        let text_layout_details = &self.text_layout_details(window);
11892        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11893            s.move_heads_with(|map, head, goal| {
11894                movement::up(map, head, goal, false, text_layout_details)
11895            })
11896        })
11897    }
11898
11899    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11900        self.take_rename(true, window, cx);
11901
11902        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11903            cx.propagate();
11904            return;
11905        }
11906
11907        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11908
11909        let text_layout_details = &self.text_layout_details(window);
11910        let selection_count = self.selections.count();
11911        let first_selection = self.selections.first_anchor();
11912
11913        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11914            s.move_with(|map, selection| {
11915                if !selection.is_empty() {
11916                    selection.goal = SelectionGoal::None;
11917                }
11918                let (cursor, goal) = movement::down(
11919                    map,
11920                    selection.end,
11921                    selection.goal,
11922                    false,
11923                    text_layout_details,
11924                );
11925                selection.collapse_to(cursor, goal);
11926            });
11927        });
11928
11929        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11930        {
11931            cx.propagate();
11932        }
11933    }
11934
11935    pub fn select_page_down(
11936        &mut self,
11937        _: &SelectPageDown,
11938        window: &mut Window,
11939        cx: &mut Context<Self>,
11940    ) {
11941        let Some(row_count) = self.visible_row_count() else {
11942            return;
11943        };
11944
11945        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11946
11947        let text_layout_details = &self.text_layout_details(window);
11948
11949        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11950            s.move_heads_with(|map, head, goal| {
11951                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11952            })
11953        })
11954    }
11955
11956    pub fn move_page_down(
11957        &mut self,
11958        action: &MovePageDown,
11959        window: &mut Window,
11960        cx: &mut Context<Self>,
11961    ) {
11962        if self.take_rename(true, window, cx).is_some() {
11963            return;
11964        }
11965
11966        if self
11967            .context_menu
11968            .borrow_mut()
11969            .as_mut()
11970            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11971            .unwrap_or(false)
11972        {
11973            return;
11974        }
11975
11976        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11977            cx.propagate();
11978            return;
11979        }
11980
11981        let Some(row_count) = self.visible_row_count() else {
11982            return;
11983        };
11984
11985        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11986
11987        let autoscroll = if action.center_cursor {
11988            Autoscroll::center()
11989        } else {
11990            Autoscroll::fit()
11991        };
11992
11993        let text_layout_details = &self.text_layout_details(window);
11994        self.change_selections(Some(autoscroll), window, cx, |s| {
11995            s.move_with(|map, selection| {
11996                if !selection.is_empty() {
11997                    selection.goal = SelectionGoal::None;
11998                }
11999                let (cursor, goal) = movement::down_by_rows(
12000                    map,
12001                    selection.end,
12002                    row_count,
12003                    selection.goal,
12004                    false,
12005                    text_layout_details,
12006                );
12007                selection.collapse_to(cursor, goal);
12008            });
12009        });
12010    }
12011
12012    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12013        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12014        let text_layout_details = &self.text_layout_details(window);
12015        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12016            s.move_heads_with(|map, head, goal| {
12017                movement::down(map, head, goal, false, text_layout_details)
12018            })
12019        });
12020    }
12021
12022    pub fn context_menu_first(
12023        &mut self,
12024        _: &ContextMenuFirst,
12025        window: &mut Window,
12026        cx: &mut Context<Self>,
12027    ) {
12028        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12029            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12030        }
12031    }
12032
12033    pub fn context_menu_prev(
12034        &mut self,
12035        _: &ContextMenuPrevious,
12036        window: &mut Window,
12037        cx: &mut Context<Self>,
12038    ) {
12039        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12040            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12041        }
12042    }
12043
12044    pub fn context_menu_next(
12045        &mut self,
12046        _: &ContextMenuNext,
12047        window: &mut Window,
12048        cx: &mut Context<Self>,
12049    ) {
12050        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12051            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12052        }
12053    }
12054
12055    pub fn context_menu_last(
12056        &mut self,
12057        _: &ContextMenuLast,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) {
12061        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12062            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12063        }
12064    }
12065
12066    pub fn move_to_previous_word_start(
12067        &mut self,
12068        _: &MoveToPreviousWordStart,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12073        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12074            s.move_cursors_with(|map, head, _| {
12075                (
12076                    movement::previous_word_start(map, head),
12077                    SelectionGoal::None,
12078                )
12079            });
12080        })
12081    }
12082
12083    pub fn move_to_previous_subword_start(
12084        &mut self,
12085        _: &MoveToPreviousSubwordStart,
12086        window: &mut Window,
12087        cx: &mut Context<Self>,
12088    ) {
12089        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12090        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12091            s.move_cursors_with(|map, head, _| {
12092                (
12093                    movement::previous_subword_start(map, head),
12094                    SelectionGoal::None,
12095                )
12096            });
12097        })
12098    }
12099
12100    pub fn select_to_previous_word_start(
12101        &mut self,
12102        _: &SelectToPreviousWordStart,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12107        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12108            s.move_heads_with(|map, head, _| {
12109                (
12110                    movement::previous_word_start(map, head),
12111                    SelectionGoal::None,
12112                )
12113            });
12114        })
12115    }
12116
12117    pub fn select_to_previous_subword_start(
12118        &mut self,
12119        _: &SelectToPreviousSubwordStart,
12120        window: &mut Window,
12121        cx: &mut Context<Self>,
12122    ) {
12123        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12124        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12125            s.move_heads_with(|map, head, _| {
12126                (
12127                    movement::previous_subword_start(map, head),
12128                    SelectionGoal::None,
12129                )
12130            });
12131        })
12132    }
12133
12134    pub fn delete_to_previous_word_start(
12135        &mut self,
12136        action: &DeleteToPreviousWordStart,
12137        window: &mut Window,
12138        cx: &mut Context<Self>,
12139    ) {
12140        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12141        self.transact(window, cx, |this, window, cx| {
12142            this.select_autoclose_pair(window, cx);
12143            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12144                s.move_with(|map, selection| {
12145                    if selection.is_empty() {
12146                        let cursor = if action.ignore_newlines {
12147                            movement::previous_word_start(map, selection.head())
12148                        } else {
12149                            movement::previous_word_start_or_newline(map, selection.head())
12150                        };
12151                        selection.set_head(cursor, SelectionGoal::None);
12152                    }
12153                });
12154            });
12155            this.insert("", window, cx);
12156        });
12157    }
12158
12159    pub fn delete_to_previous_subword_start(
12160        &mut self,
12161        _: &DeleteToPreviousSubwordStart,
12162        window: &mut Window,
12163        cx: &mut Context<Self>,
12164    ) {
12165        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12166        self.transact(window, cx, |this, window, cx| {
12167            this.select_autoclose_pair(window, cx);
12168            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12169                s.move_with(|map, selection| {
12170                    if selection.is_empty() {
12171                        let cursor = movement::previous_subword_start(map, selection.head());
12172                        selection.set_head(cursor, SelectionGoal::None);
12173                    }
12174                });
12175            });
12176            this.insert("", window, cx);
12177        });
12178    }
12179
12180    pub fn move_to_next_word_end(
12181        &mut self,
12182        _: &MoveToNextWordEnd,
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_cursors_with(|map, head, _| {
12189                (movement::next_word_end(map, head), SelectionGoal::None)
12190            });
12191        })
12192    }
12193
12194    pub fn move_to_next_subword_end(
12195        &mut self,
12196        _: &MoveToNextSubwordEnd,
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_cursors_with(|map, head, _| {
12203                (movement::next_subword_end(map, head), SelectionGoal::None)
12204            });
12205        })
12206    }
12207
12208    pub fn select_to_next_word_end(
12209        &mut self,
12210        _: &SelectToNextWordEnd,
12211        window: &mut Window,
12212        cx: &mut Context<Self>,
12213    ) {
12214        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12215        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12216            s.move_heads_with(|map, head, _| {
12217                (movement::next_word_end(map, head), SelectionGoal::None)
12218            });
12219        })
12220    }
12221
12222    pub fn select_to_next_subword_end(
12223        &mut self,
12224        _: &SelectToNextSubwordEnd,
12225        window: &mut Window,
12226        cx: &mut Context<Self>,
12227    ) {
12228        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12229        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12230            s.move_heads_with(|map, head, _| {
12231                (movement::next_subword_end(map, head), SelectionGoal::None)
12232            });
12233        })
12234    }
12235
12236    pub fn delete_to_next_word_end(
12237        &mut self,
12238        action: &DeleteToNextWordEnd,
12239        window: &mut Window,
12240        cx: &mut Context<Self>,
12241    ) {
12242        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12243        self.transact(window, cx, |this, window, cx| {
12244            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12245                s.move_with(|map, selection| {
12246                    if selection.is_empty() {
12247                        let cursor = if action.ignore_newlines {
12248                            movement::next_word_end(map, selection.head())
12249                        } else {
12250                            movement::next_word_end_or_newline(map, selection.head())
12251                        };
12252                        selection.set_head(cursor, SelectionGoal::None);
12253                    }
12254                });
12255            });
12256            this.insert("", window, cx);
12257        });
12258    }
12259
12260    pub fn delete_to_next_subword_end(
12261        &mut self,
12262        _: &DeleteToNextSubwordEnd,
12263        window: &mut Window,
12264        cx: &mut Context<Self>,
12265    ) {
12266        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12267        self.transact(window, cx, |this, window, cx| {
12268            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12269                s.move_with(|map, selection| {
12270                    if selection.is_empty() {
12271                        let cursor = movement::next_subword_end(map, selection.head());
12272                        selection.set_head(cursor, SelectionGoal::None);
12273                    }
12274                });
12275            });
12276            this.insert("", window, cx);
12277        });
12278    }
12279
12280    pub fn move_to_beginning_of_line(
12281        &mut self,
12282        action: &MoveToBeginningOfLine,
12283        window: &mut Window,
12284        cx: &mut Context<Self>,
12285    ) {
12286        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12287        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12288            s.move_cursors_with(|map, head, _| {
12289                (
12290                    movement::indented_line_beginning(
12291                        map,
12292                        head,
12293                        action.stop_at_soft_wraps,
12294                        action.stop_at_indent,
12295                    ),
12296                    SelectionGoal::None,
12297                )
12298            });
12299        })
12300    }
12301
12302    pub fn select_to_beginning_of_line(
12303        &mut self,
12304        action: &SelectToBeginningOfLine,
12305        window: &mut Window,
12306        cx: &mut Context<Self>,
12307    ) {
12308        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12309        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12310            s.move_heads_with(|map, head, _| {
12311                (
12312                    movement::indented_line_beginning(
12313                        map,
12314                        head,
12315                        action.stop_at_soft_wraps,
12316                        action.stop_at_indent,
12317                    ),
12318                    SelectionGoal::None,
12319                )
12320            });
12321        });
12322    }
12323
12324    pub fn delete_to_beginning_of_line(
12325        &mut self,
12326        action: &DeleteToBeginningOfLine,
12327        window: &mut Window,
12328        cx: &mut Context<Self>,
12329    ) {
12330        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12331        self.transact(window, cx, |this, window, cx| {
12332            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12333                s.move_with(|_, selection| {
12334                    selection.reversed = true;
12335                });
12336            });
12337
12338            this.select_to_beginning_of_line(
12339                &SelectToBeginningOfLine {
12340                    stop_at_soft_wraps: false,
12341                    stop_at_indent: action.stop_at_indent,
12342                },
12343                window,
12344                cx,
12345            );
12346            this.backspace(&Backspace, window, cx);
12347        });
12348    }
12349
12350    pub fn move_to_end_of_line(
12351        &mut self,
12352        action: &MoveToEndOfLine,
12353        window: &mut Window,
12354        cx: &mut Context<Self>,
12355    ) {
12356        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12357        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12358            s.move_cursors_with(|map, head, _| {
12359                (
12360                    movement::line_end(map, head, action.stop_at_soft_wraps),
12361                    SelectionGoal::None,
12362                )
12363            });
12364        })
12365    }
12366
12367    pub fn select_to_end_of_line(
12368        &mut self,
12369        action: &SelectToEndOfLine,
12370        window: &mut Window,
12371        cx: &mut Context<Self>,
12372    ) {
12373        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12374        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12375            s.move_heads_with(|map, head, _| {
12376                (
12377                    movement::line_end(map, head, action.stop_at_soft_wraps),
12378                    SelectionGoal::None,
12379                )
12380            });
12381        })
12382    }
12383
12384    pub fn delete_to_end_of_line(
12385        &mut self,
12386        _: &DeleteToEndOfLine,
12387        window: &mut Window,
12388        cx: &mut Context<Self>,
12389    ) {
12390        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12391        self.transact(window, cx, |this, window, cx| {
12392            this.select_to_end_of_line(
12393                &SelectToEndOfLine {
12394                    stop_at_soft_wraps: false,
12395                },
12396                window,
12397                cx,
12398            );
12399            this.delete(&Delete, window, cx);
12400        });
12401    }
12402
12403    pub fn cut_to_end_of_line(
12404        &mut self,
12405        _: &CutToEndOfLine,
12406        window: &mut Window,
12407        cx: &mut Context<Self>,
12408    ) {
12409        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12410        self.transact(window, cx, |this, window, cx| {
12411            this.select_to_end_of_line(
12412                &SelectToEndOfLine {
12413                    stop_at_soft_wraps: false,
12414                },
12415                window,
12416                cx,
12417            );
12418            this.cut(&Cut, window, cx);
12419        });
12420    }
12421
12422    pub fn move_to_start_of_paragraph(
12423        &mut self,
12424        _: &MoveToStartOfParagraph,
12425        window: &mut Window,
12426        cx: &mut Context<Self>,
12427    ) {
12428        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12429            cx.propagate();
12430            return;
12431        }
12432        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12433        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12434            s.move_with(|map, selection| {
12435                selection.collapse_to(
12436                    movement::start_of_paragraph(map, selection.head(), 1),
12437                    SelectionGoal::None,
12438                )
12439            });
12440        })
12441    }
12442
12443    pub fn move_to_end_of_paragraph(
12444        &mut self,
12445        _: &MoveToEndOfParagraph,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12450            cx.propagate();
12451            return;
12452        }
12453        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12454        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12455            s.move_with(|map, selection| {
12456                selection.collapse_to(
12457                    movement::end_of_paragraph(map, selection.head(), 1),
12458                    SelectionGoal::None,
12459                )
12460            });
12461        })
12462    }
12463
12464    pub fn select_to_start_of_paragraph(
12465        &mut self,
12466        _: &SelectToStartOfParagraph,
12467        window: &mut Window,
12468        cx: &mut Context<Self>,
12469    ) {
12470        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12471            cx.propagate();
12472            return;
12473        }
12474        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12475        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12476            s.move_heads_with(|map, head, _| {
12477                (
12478                    movement::start_of_paragraph(map, head, 1),
12479                    SelectionGoal::None,
12480                )
12481            });
12482        })
12483    }
12484
12485    pub fn select_to_end_of_paragraph(
12486        &mut self,
12487        _: &SelectToEndOfParagraph,
12488        window: &mut Window,
12489        cx: &mut Context<Self>,
12490    ) {
12491        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12492            cx.propagate();
12493            return;
12494        }
12495        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12496        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12497            s.move_heads_with(|map, head, _| {
12498                (
12499                    movement::end_of_paragraph(map, head, 1),
12500                    SelectionGoal::None,
12501                )
12502            });
12503        })
12504    }
12505
12506    pub fn move_to_start_of_excerpt(
12507        &mut self,
12508        _: &MoveToStartOfExcerpt,
12509        window: &mut Window,
12510        cx: &mut Context<Self>,
12511    ) {
12512        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12513            cx.propagate();
12514            return;
12515        }
12516        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12517        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12518            s.move_with(|map, selection| {
12519                selection.collapse_to(
12520                    movement::start_of_excerpt(
12521                        map,
12522                        selection.head(),
12523                        workspace::searchable::Direction::Prev,
12524                    ),
12525                    SelectionGoal::None,
12526                )
12527            });
12528        })
12529    }
12530
12531    pub fn move_to_start_of_next_excerpt(
12532        &mut self,
12533        _: &MoveToStartOfNextExcerpt,
12534        window: &mut Window,
12535        cx: &mut Context<Self>,
12536    ) {
12537        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12538            cx.propagate();
12539            return;
12540        }
12541
12542        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12543            s.move_with(|map, selection| {
12544                selection.collapse_to(
12545                    movement::start_of_excerpt(
12546                        map,
12547                        selection.head(),
12548                        workspace::searchable::Direction::Next,
12549                    ),
12550                    SelectionGoal::None,
12551                )
12552            });
12553        })
12554    }
12555
12556    pub fn move_to_end_of_excerpt(
12557        &mut self,
12558        _: &MoveToEndOfExcerpt,
12559        window: &mut Window,
12560        cx: &mut Context<Self>,
12561    ) {
12562        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12563            cx.propagate();
12564            return;
12565        }
12566        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12567        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12568            s.move_with(|map, selection| {
12569                selection.collapse_to(
12570                    movement::end_of_excerpt(
12571                        map,
12572                        selection.head(),
12573                        workspace::searchable::Direction::Next,
12574                    ),
12575                    SelectionGoal::None,
12576                )
12577            });
12578        })
12579    }
12580
12581    pub fn move_to_end_of_previous_excerpt(
12582        &mut self,
12583        _: &MoveToEndOfPreviousExcerpt,
12584        window: &mut Window,
12585        cx: &mut Context<Self>,
12586    ) {
12587        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12588            cx.propagate();
12589            return;
12590        }
12591        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12592        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12593            s.move_with(|map, selection| {
12594                selection.collapse_to(
12595                    movement::end_of_excerpt(
12596                        map,
12597                        selection.head(),
12598                        workspace::searchable::Direction::Prev,
12599                    ),
12600                    SelectionGoal::None,
12601                )
12602            });
12603        })
12604    }
12605
12606    pub fn select_to_start_of_excerpt(
12607        &mut self,
12608        _: &SelectToStartOfExcerpt,
12609        window: &mut Window,
12610        cx: &mut Context<Self>,
12611    ) {
12612        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12613            cx.propagate();
12614            return;
12615        }
12616        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12617        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12618            s.move_heads_with(|map, head, _| {
12619                (
12620                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12621                    SelectionGoal::None,
12622                )
12623            });
12624        })
12625    }
12626
12627    pub fn select_to_start_of_next_excerpt(
12628        &mut self,
12629        _: &SelectToStartOfNextExcerpt,
12630        window: &mut Window,
12631        cx: &mut Context<Self>,
12632    ) {
12633        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12634            cx.propagate();
12635            return;
12636        }
12637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12638        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12639            s.move_heads_with(|map, head, _| {
12640                (
12641                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12642                    SelectionGoal::None,
12643                )
12644            });
12645        })
12646    }
12647
12648    pub fn select_to_end_of_excerpt(
12649        &mut self,
12650        _: &SelectToEndOfExcerpt,
12651        window: &mut Window,
12652        cx: &mut Context<Self>,
12653    ) {
12654        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12655            cx.propagate();
12656            return;
12657        }
12658        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12659        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12660            s.move_heads_with(|map, head, _| {
12661                (
12662                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12663                    SelectionGoal::None,
12664                )
12665            });
12666        })
12667    }
12668
12669    pub fn select_to_end_of_previous_excerpt(
12670        &mut self,
12671        _: &SelectToEndOfPreviousExcerpt,
12672        window: &mut Window,
12673        cx: &mut Context<Self>,
12674    ) {
12675        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12676            cx.propagate();
12677            return;
12678        }
12679        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12680        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12681            s.move_heads_with(|map, head, _| {
12682                (
12683                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12684                    SelectionGoal::None,
12685                )
12686            });
12687        })
12688    }
12689
12690    pub fn move_to_beginning(
12691        &mut self,
12692        _: &MoveToBeginning,
12693        window: &mut Window,
12694        cx: &mut Context<Self>,
12695    ) {
12696        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12697            cx.propagate();
12698            return;
12699        }
12700        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12701        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12702            s.select_ranges(vec![0..0]);
12703        });
12704    }
12705
12706    pub fn select_to_beginning(
12707        &mut self,
12708        _: &SelectToBeginning,
12709        window: &mut Window,
12710        cx: &mut Context<Self>,
12711    ) {
12712        let mut selection = self.selections.last::<Point>(cx);
12713        selection.set_head(Point::zero(), SelectionGoal::None);
12714        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12715        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12716            s.select(vec![selection]);
12717        });
12718    }
12719
12720    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12721        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12722            cx.propagate();
12723            return;
12724        }
12725        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12726        let cursor = self.buffer.read(cx).read(cx).len();
12727        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12728            s.select_ranges(vec![cursor..cursor])
12729        });
12730    }
12731
12732    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12733        self.nav_history = nav_history;
12734    }
12735
12736    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12737        self.nav_history.as_ref()
12738    }
12739
12740    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12741        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12742    }
12743
12744    fn push_to_nav_history(
12745        &mut self,
12746        cursor_anchor: Anchor,
12747        new_position: Option<Point>,
12748        is_deactivate: bool,
12749        cx: &mut Context<Self>,
12750    ) {
12751        if let Some(nav_history) = self.nav_history.as_mut() {
12752            let buffer = self.buffer.read(cx).read(cx);
12753            let cursor_position = cursor_anchor.to_point(&buffer);
12754            let scroll_state = self.scroll_manager.anchor();
12755            let scroll_top_row = scroll_state.top_row(&buffer);
12756            drop(buffer);
12757
12758            if let Some(new_position) = new_position {
12759                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12760                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12761                    return;
12762                }
12763            }
12764
12765            nav_history.push(
12766                Some(NavigationData {
12767                    cursor_anchor,
12768                    cursor_position,
12769                    scroll_anchor: scroll_state,
12770                    scroll_top_row,
12771                }),
12772                cx,
12773            );
12774            cx.emit(EditorEvent::PushedToNavHistory {
12775                anchor: cursor_anchor,
12776                is_deactivate,
12777            })
12778        }
12779    }
12780
12781    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12782        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12783        let buffer = self.buffer.read(cx).snapshot(cx);
12784        let mut selection = self.selections.first::<usize>(cx);
12785        selection.set_head(buffer.len(), SelectionGoal::None);
12786        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12787            s.select(vec![selection]);
12788        });
12789    }
12790
12791    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12792        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12793        let end = self.buffer.read(cx).read(cx).len();
12794        self.change_selections(None, window, cx, |s| {
12795            s.select_ranges(vec![0..end]);
12796        });
12797    }
12798
12799    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12800        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12801        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12802        let mut selections = self.selections.all::<Point>(cx);
12803        let max_point = display_map.buffer_snapshot.max_point();
12804        for selection in &mut selections {
12805            let rows = selection.spanned_rows(true, &display_map);
12806            selection.start = Point::new(rows.start.0, 0);
12807            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12808            selection.reversed = false;
12809        }
12810        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12811            s.select(selections);
12812        });
12813    }
12814
12815    pub fn split_selection_into_lines(
12816        &mut self,
12817        _: &SplitSelectionIntoLines,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        let selections = self
12822            .selections
12823            .all::<Point>(cx)
12824            .into_iter()
12825            .map(|selection| selection.start..selection.end)
12826            .collect::<Vec<_>>();
12827        self.unfold_ranges(&selections, true, true, cx);
12828
12829        let mut new_selection_ranges = Vec::new();
12830        {
12831            let buffer = self.buffer.read(cx).read(cx);
12832            for selection in selections {
12833                for row in selection.start.row..selection.end.row {
12834                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12835                    new_selection_ranges.push(cursor..cursor);
12836                }
12837
12838                let is_multiline_selection = selection.start.row != selection.end.row;
12839                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12840                // so this action feels more ergonomic when paired with other selection operations
12841                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12842                if !should_skip_last {
12843                    new_selection_ranges.push(selection.end..selection.end);
12844                }
12845            }
12846        }
12847        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12848            s.select_ranges(new_selection_ranges);
12849        });
12850    }
12851
12852    pub fn add_selection_above(
12853        &mut self,
12854        _: &AddSelectionAbove,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        self.add_selection(true, window, cx);
12859    }
12860
12861    pub fn add_selection_below(
12862        &mut self,
12863        _: &AddSelectionBelow,
12864        window: &mut Window,
12865        cx: &mut Context<Self>,
12866    ) {
12867        self.add_selection(false, window, cx);
12868    }
12869
12870    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12871        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12872
12873        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12874        let all_selections = self.selections.all::<Point>(cx);
12875        let text_layout_details = self.text_layout_details(window);
12876
12877        let (mut columnar_selections, new_selections_to_columnarize) = {
12878            if let Some(state) = self.add_selections_state.as_ref() {
12879                let columnar_selection_ids: HashSet<_> = state
12880                    .groups
12881                    .iter()
12882                    .flat_map(|group| group.stack.iter())
12883                    .copied()
12884                    .collect();
12885
12886                all_selections
12887                    .into_iter()
12888                    .partition(|s| columnar_selection_ids.contains(&s.id))
12889            } else {
12890                (Vec::new(), all_selections)
12891            }
12892        };
12893
12894        let mut state = self
12895            .add_selections_state
12896            .take()
12897            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12898
12899        for selection in new_selections_to_columnarize {
12900            let range = selection.display_range(&display_map).sorted();
12901            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12902            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12903            let positions = start_x.min(end_x)..start_x.max(end_x);
12904            let mut stack = Vec::new();
12905            for row in range.start.row().0..=range.end.row().0 {
12906                if let Some(selection) = self.selections.build_columnar_selection(
12907                    &display_map,
12908                    DisplayRow(row),
12909                    &positions,
12910                    selection.reversed,
12911                    &text_layout_details,
12912                ) {
12913                    stack.push(selection.id);
12914                    columnar_selections.push(selection);
12915                }
12916            }
12917            if !stack.is_empty() {
12918                if above {
12919                    stack.reverse();
12920                }
12921                state.groups.push(AddSelectionsGroup { above, stack });
12922            }
12923        }
12924
12925        let mut final_selections = Vec::new();
12926        let end_row = if above {
12927            DisplayRow(0)
12928        } else {
12929            display_map.max_point().row()
12930        };
12931
12932        let mut last_added_item_per_group = HashMap::default();
12933        for group in state.groups.iter_mut() {
12934            if let Some(last_id) = group.stack.last() {
12935                last_added_item_per_group.insert(*last_id, group);
12936            }
12937        }
12938
12939        for selection in columnar_selections {
12940            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12941                if above == group.above {
12942                    let range = selection.display_range(&display_map).sorted();
12943                    debug_assert_eq!(range.start.row(), range.end.row());
12944                    let mut row = range.start.row();
12945                    let positions =
12946                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12947                            px(start)..px(end)
12948                        } else {
12949                            let start_x =
12950                                display_map.x_for_display_point(range.start, &text_layout_details);
12951                            let end_x =
12952                                display_map.x_for_display_point(range.end, &text_layout_details);
12953                            start_x.min(end_x)..start_x.max(end_x)
12954                        };
12955
12956                    let mut maybe_new_selection = None;
12957                    while row != end_row {
12958                        if above {
12959                            row.0 -= 1;
12960                        } else {
12961                            row.0 += 1;
12962                        }
12963                        if let Some(new_selection) = self.selections.build_columnar_selection(
12964                            &display_map,
12965                            row,
12966                            &positions,
12967                            selection.reversed,
12968                            &text_layout_details,
12969                        ) {
12970                            maybe_new_selection = Some(new_selection);
12971                            break;
12972                        }
12973                    }
12974
12975                    if let Some(new_selection) = maybe_new_selection {
12976                        group.stack.push(new_selection.id);
12977                        if above {
12978                            final_selections.push(new_selection);
12979                            final_selections.push(selection);
12980                        } else {
12981                            final_selections.push(selection);
12982                            final_selections.push(new_selection);
12983                        }
12984                    } else {
12985                        final_selections.push(selection);
12986                    }
12987                } else {
12988                    group.stack.pop();
12989                }
12990            } else {
12991                final_selections.push(selection);
12992            }
12993        }
12994
12995        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12996            s.select(final_selections);
12997        });
12998
12999        let final_selection_ids: HashSet<_> = self
13000            .selections
13001            .all::<Point>(cx)
13002            .iter()
13003            .map(|s| s.id)
13004            .collect();
13005        state.groups.retain_mut(|group| {
13006            // selections might get merged above so we remove invalid items from stacks
13007            group.stack.retain(|id| final_selection_ids.contains(id));
13008
13009            // single selection in stack can be treated as initial state
13010            group.stack.len() > 1
13011        });
13012
13013        if !state.groups.is_empty() {
13014            self.add_selections_state = Some(state);
13015        }
13016    }
13017
13018    fn select_match_ranges(
13019        &mut self,
13020        range: Range<usize>,
13021        reversed: bool,
13022        replace_newest: bool,
13023        auto_scroll: Option<Autoscroll>,
13024        window: &mut Window,
13025        cx: &mut Context<Editor>,
13026    ) {
13027        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13028        self.change_selections(auto_scroll, window, cx, |s| {
13029            if replace_newest {
13030                s.delete(s.newest_anchor().id);
13031            }
13032            if reversed {
13033                s.insert_range(range.end..range.start);
13034            } else {
13035                s.insert_range(range);
13036            }
13037        });
13038    }
13039
13040    pub fn select_next_match_internal(
13041        &mut self,
13042        display_map: &DisplaySnapshot,
13043        replace_newest: bool,
13044        autoscroll: Option<Autoscroll>,
13045        window: &mut Window,
13046        cx: &mut Context<Self>,
13047    ) -> Result<()> {
13048        let buffer = &display_map.buffer_snapshot;
13049        let mut selections = self.selections.all::<usize>(cx);
13050        if let Some(mut select_next_state) = self.select_next_state.take() {
13051            let query = &select_next_state.query;
13052            if !select_next_state.done {
13053                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13054                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13055                let mut next_selected_range = None;
13056
13057                let bytes_after_last_selection =
13058                    buffer.bytes_in_range(last_selection.end..buffer.len());
13059                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13060                let query_matches = query
13061                    .stream_find_iter(bytes_after_last_selection)
13062                    .map(|result| (last_selection.end, result))
13063                    .chain(
13064                        query
13065                            .stream_find_iter(bytes_before_first_selection)
13066                            .map(|result| (0, result)),
13067                    );
13068
13069                for (start_offset, query_match) in query_matches {
13070                    let query_match = query_match.unwrap(); // can only fail due to I/O
13071                    let offset_range =
13072                        start_offset + query_match.start()..start_offset + query_match.end();
13073                    let display_range = offset_range.start.to_display_point(display_map)
13074                        ..offset_range.end.to_display_point(display_map);
13075
13076                    if !select_next_state.wordwise
13077                        || (!movement::is_inside_word(display_map, display_range.start)
13078                            && !movement::is_inside_word(display_map, display_range.end))
13079                    {
13080                        // TODO: This is n^2, because we might check all the selections
13081                        if !selections
13082                            .iter()
13083                            .any(|selection| selection.range().overlaps(&offset_range))
13084                        {
13085                            next_selected_range = Some(offset_range);
13086                            break;
13087                        }
13088                    }
13089                }
13090
13091                if let Some(next_selected_range) = next_selected_range {
13092                    self.select_match_ranges(
13093                        next_selected_range,
13094                        last_selection.reversed,
13095                        replace_newest,
13096                        autoscroll,
13097                        window,
13098                        cx,
13099                    );
13100                } else {
13101                    select_next_state.done = true;
13102                }
13103            }
13104
13105            self.select_next_state = Some(select_next_state);
13106        } else {
13107            let mut only_carets = true;
13108            let mut same_text_selected = true;
13109            let mut selected_text = None;
13110
13111            let mut selections_iter = selections.iter().peekable();
13112            while let Some(selection) = selections_iter.next() {
13113                if selection.start != selection.end {
13114                    only_carets = false;
13115                }
13116
13117                if same_text_selected {
13118                    if selected_text.is_none() {
13119                        selected_text =
13120                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13121                    }
13122
13123                    if let Some(next_selection) = selections_iter.peek() {
13124                        if next_selection.range().len() == selection.range().len() {
13125                            let next_selected_text = buffer
13126                                .text_for_range(next_selection.range())
13127                                .collect::<String>();
13128                            if Some(next_selected_text) != selected_text {
13129                                same_text_selected = false;
13130                                selected_text = None;
13131                            }
13132                        } else {
13133                            same_text_selected = false;
13134                            selected_text = None;
13135                        }
13136                    }
13137                }
13138            }
13139
13140            if only_carets {
13141                for selection in &mut selections {
13142                    let word_range = movement::surrounding_word(
13143                        display_map,
13144                        selection.start.to_display_point(display_map),
13145                    );
13146                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13147                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13148                    selection.goal = SelectionGoal::None;
13149                    selection.reversed = false;
13150                    self.select_match_ranges(
13151                        selection.start..selection.end,
13152                        selection.reversed,
13153                        replace_newest,
13154                        autoscroll,
13155                        window,
13156                        cx,
13157                    );
13158                }
13159
13160                if selections.len() == 1 {
13161                    let selection = selections
13162                        .last()
13163                        .expect("ensured that there's only one selection");
13164                    let query = buffer
13165                        .text_for_range(selection.start..selection.end)
13166                        .collect::<String>();
13167                    let is_empty = query.is_empty();
13168                    let select_state = SelectNextState {
13169                        query: AhoCorasick::new(&[query])?,
13170                        wordwise: true,
13171                        done: is_empty,
13172                    };
13173                    self.select_next_state = Some(select_state);
13174                } else {
13175                    self.select_next_state = None;
13176                }
13177            } else if let Some(selected_text) = selected_text {
13178                self.select_next_state = Some(SelectNextState {
13179                    query: AhoCorasick::new(&[selected_text])?,
13180                    wordwise: false,
13181                    done: false,
13182                });
13183                self.select_next_match_internal(
13184                    display_map,
13185                    replace_newest,
13186                    autoscroll,
13187                    window,
13188                    cx,
13189                )?;
13190            }
13191        }
13192        Ok(())
13193    }
13194
13195    pub fn select_all_matches(
13196        &mut self,
13197        _action: &SelectAllMatches,
13198        window: &mut Window,
13199        cx: &mut Context<Self>,
13200    ) -> Result<()> {
13201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13202
13203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13204
13205        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13206        let Some(select_next_state) = self.select_next_state.as_mut() else {
13207            return Ok(());
13208        };
13209        if select_next_state.done {
13210            return Ok(());
13211        }
13212
13213        let mut new_selections = Vec::new();
13214
13215        let reversed = self.selections.oldest::<usize>(cx).reversed;
13216        let buffer = &display_map.buffer_snapshot;
13217        let query_matches = select_next_state
13218            .query
13219            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13220
13221        for query_match in query_matches.into_iter() {
13222            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13223            let offset_range = if reversed {
13224                query_match.end()..query_match.start()
13225            } else {
13226                query_match.start()..query_match.end()
13227            };
13228            let display_range = offset_range.start.to_display_point(&display_map)
13229                ..offset_range.end.to_display_point(&display_map);
13230
13231            if !select_next_state.wordwise
13232                || (!movement::is_inside_word(&display_map, display_range.start)
13233                    && !movement::is_inside_word(&display_map, display_range.end))
13234            {
13235                new_selections.push(offset_range.start..offset_range.end);
13236            }
13237        }
13238
13239        select_next_state.done = true;
13240        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13241        self.change_selections(None, window, cx, |selections| {
13242            selections.select_ranges(new_selections)
13243        });
13244
13245        Ok(())
13246    }
13247
13248    pub fn select_next(
13249        &mut self,
13250        action: &SelectNext,
13251        window: &mut Window,
13252        cx: &mut Context<Self>,
13253    ) -> Result<()> {
13254        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13255        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13256        self.select_next_match_internal(
13257            &display_map,
13258            action.replace_newest,
13259            Some(Autoscroll::newest()),
13260            window,
13261            cx,
13262        )?;
13263        Ok(())
13264    }
13265
13266    pub fn select_previous(
13267        &mut self,
13268        action: &SelectPrevious,
13269        window: &mut Window,
13270        cx: &mut Context<Self>,
13271    ) -> Result<()> {
13272        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13273        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13274        let buffer = &display_map.buffer_snapshot;
13275        let mut selections = self.selections.all::<usize>(cx);
13276        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13277            let query = &select_prev_state.query;
13278            if !select_prev_state.done {
13279                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13280                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13281                let mut next_selected_range = None;
13282                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13283                let bytes_before_last_selection =
13284                    buffer.reversed_bytes_in_range(0..last_selection.start);
13285                let bytes_after_first_selection =
13286                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13287                let query_matches = query
13288                    .stream_find_iter(bytes_before_last_selection)
13289                    .map(|result| (last_selection.start, result))
13290                    .chain(
13291                        query
13292                            .stream_find_iter(bytes_after_first_selection)
13293                            .map(|result| (buffer.len(), result)),
13294                    );
13295                for (end_offset, query_match) in query_matches {
13296                    let query_match = query_match.unwrap(); // can only fail due to I/O
13297                    let offset_range =
13298                        end_offset - query_match.end()..end_offset - query_match.start();
13299                    let display_range = offset_range.start.to_display_point(&display_map)
13300                        ..offset_range.end.to_display_point(&display_map);
13301
13302                    if !select_prev_state.wordwise
13303                        || (!movement::is_inside_word(&display_map, display_range.start)
13304                            && !movement::is_inside_word(&display_map, display_range.end))
13305                    {
13306                        next_selected_range = Some(offset_range);
13307                        break;
13308                    }
13309                }
13310
13311                if let Some(next_selected_range) = next_selected_range {
13312                    self.select_match_ranges(
13313                        next_selected_range,
13314                        last_selection.reversed,
13315                        action.replace_newest,
13316                        Some(Autoscroll::newest()),
13317                        window,
13318                        cx,
13319                    );
13320                } else {
13321                    select_prev_state.done = true;
13322                }
13323            }
13324
13325            self.select_prev_state = Some(select_prev_state);
13326        } else {
13327            let mut only_carets = true;
13328            let mut same_text_selected = true;
13329            let mut selected_text = None;
13330
13331            let mut selections_iter = selections.iter().peekable();
13332            while let Some(selection) = selections_iter.next() {
13333                if selection.start != selection.end {
13334                    only_carets = false;
13335                }
13336
13337                if same_text_selected {
13338                    if selected_text.is_none() {
13339                        selected_text =
13340                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13341                    }
13342
13343                    if let Some(next_selection) = selections_iter.peek() {
13344                        if next_selection.range().len() == selection.range().len() {
13345                            let next_selected_text = buffer
13346                                .text_for_range(next_selection.range())
13347                                .collect::<String>();
13348                            if Some(next_selected_text) != selected_text {
13349                                same_text_selected = false;
13350                                selected_text = None;
13351                            }
13352                        } else {
13353                            same_text_selected = false;
13354                            selected_text = None;
13355                        }
13356                    }
13357                }
13358            }
13359
13360            if only_carets {
13361                for selection in &mut selections {
13362                    let word_range = movement::surrounding_word(
13363                        &display_map,
13364                        selection.start.to_display_point(&display_map),
13365                    );
13366                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13367                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13368                    selection.goal = SelectionGoal::None;
13369                    selection.reversed = false;
13370                    self.select_match_ranges(
13371                        selection.start..selection.end,
13372                        selection.reversed,
13373                        action.replace_newest,
13374                        Some(Autoscroll::newest()),
13375                        window,
13376                        cx,
13377                    );
13378                }
13379                if selections.len() == 1 {
13380                    let selection = selections
13381                        .last()
13382                        .expect("ensured that there's only one selection");
13383                    let query = buffer
13384                        .text_for_range(selection.start..selection.end)
13385                        .collect::<String>();
13386                    let is_empty = query.is_empty();
13387                    let select_state = SelectNextState {
13388                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13389                        wordwise: true,
13390                        done: is_empty,
13391                    };
13392                    self.select_prev_state = Some(select_state);
13393                } else {
13394                    self.select_prev_state = None;
13395                }
13396            } else if let Some(selected_text) = selected_text {
13397                self.select_prev_state = Some(SelectNextState {
13398                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13399                    wordwise: false,
13400                    done: false,
13401                });
13402                self.select_previous(action, window, cx)?;
13403            }
13404        }
13405        Ok(())
13406    }
13407
13408    pub fn find_next_match(
13409        &mut self,
13410        _: &FindNextMatch,
13411        window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) -> Result<()> {
13414        let selections = self.selections.disjoint_anchors();
13415        match selections.first() {
13416            Some(first) if selections.len() >= 2 => {
13417                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13418                    s.select_ranges([first.range()]);
13419                });
13420            }
13421            _ => self.select_next(
13422                &SelectNext {
13423                    replace_newest: true,
13424                },
13425                window,
13426                cx,
13427            )?,
13428        }
13429        Ok(())
13430    }
13431
13432    pub fn find_previous_match(
13433        &mut self,
13434        _: &FindPreviousMatch,
13435        window: &mut Window,
13436        cx: &mut Context<Self>,
13437    ) -> Result<()> {
13438        let selections = self.selections.disjoint_anchors();
13439        match selections.last() {
13440            Some(last) if selections.len() >= 2 => {
13441                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13442                    s.select_ranges([last.range()]);
13443                });
13444            }
13445            _ => self.select_previous(
13446                &SelectPrevious {
13447                    replace_newest: true,
13448                },
13449                window,
13450                cx,
13451            )?,
13452        }
13453        Ok(())
13454    }
13455
13456    pub fn toggle_comments(
13457        &mut self,
13458        action: &ToggleComments,
13459        window: &mut Window,
13460        cx: &mut Context<Self>,
13461    ) {
13462        if self.read_only(cx) {
13463            return;
13464        }
13465        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13466        let text_layout_details = &self.text_layout_details(window);
13467        self.transact(window, cx, |this, window, cx| {
13468            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13469            let mut edits = Vec::new();
13470            let mut selection_edit_ranges = Vec::new();
13471            let mut last_toggled_row = None;
13472            let snapshot = this.buffer.read(cx).read(cx);
13473            let empty_str: Arc<str> = Arc::default();
13474            let mut suffixes_inserted = Vec::new();
13475            let ignore_indent = action.ignore_indent;
13476
13477            fn comment_prefix_range(
13478                snapshot: &MultiBufferSnapshot,
13479                row: MultiBufferRow,
13480                comment_prefix: &str,
13481                comment_prefix_whitespace: &str,
13482                ignore_indent: bool,
13483            ) -> Range<Point> {
13484                let indent_size = if ignore_indent {
13485                    0
13486                } else {
13487                    snapshot.indent_size_for_line(row).len
13488                };
13489
13490                let start = Point::new(row.0, indent_size);
13491
13492                let mut line_bytes = snapshot
13493                    .bytes_in_range(start..snapshot.max_point())
13494                    .flatten()
13495                    .copied();
13496
13497                // If this line currently begins with the line comment prefix, then record
13498                // the range containing the prefix.
13499                if line_bytes
13500                    .by_ref()
13501                    .take(comment_prefix.len())
13502                    .eq(comment_prefix.bytes())
13503                {
13504                    // Include any whitespace that matches the comment prefix.
13505                    let matching_whitespace_len = line_bytes
13506                        .zip(comment_prefix_whitespace.bytes())
13507                        .take_while(|(a, b)| a == b)
13508                        .count() as u32;
13509                    let end = Point::new(
13510                        start.row,
13511                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13512                    );
13513                    start..end
13514                } else {
13515                    start..start
13516                }
13517            }
13518
13519            fn comment_suffix_range(
13520                snapshot: &MultiBufferSnapshot,
13521                row: MultiBufferRow,
13522                comment_suffix: &str,
13523                comment_suffix_has_leading_space: bool,
13524            ) -> Range<Point> {
13525                let end = Point::new(row.0, snapshot.line_len(row));
13526                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13527
13528                let mut line_end_bytes = snapshot
13529                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13530                    .flatten()
13531                    .copied();
13532
13533                let leading_space_len = if suffix_start_column > 0
13534                    && line_end_bytes.next() == Some(b' ')
13535                    && comment_suffix_has_leading_space
13536                {
13537                    1
13538                } else {
13539                    0
13540                };
13541
13542                // If this line currently begins with the line comment prefix, then record
13543                // the range containing the prefix.
13544                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13545                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13546                    start..end
13547                } else {
13548                    end..end
13549                }
13550            }
13551
13552            // TODO: Handle selections that cross excerpts
13553            for selection in &mut selections {
13554                let start_column = snapshot
13555                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13556                    .len;
13557                let language = if let Some(language) =
13558                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13559                {
13560                    language
13561                } else {
13562                    continue;
13563                };
13564
13565                selection_edit_ranges.clear();
13566
13567                // If multiple selections contain a given row, avoid processing that
13568                // row more than once.
13569                let mut start_row = MultiBufferRow(selection.start.row);
13570                if last_toggled_row == Some(start_row) {
13571                    start_row = start_row.next_row();
13572                }
13573                let end_row =
13574                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13575                        MultiBufferRow(selection.end.row - 1)
13576                    } else {
13577                        MultiBufferRow(selection.end.row)
13578                    };
13579                last_toggled_row = Some(end_row);
13580
13581                if start_row > end_row {
13582                    continue;
13583                }
13584
13585                // If the language has line comments, toggle those.
13586                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13587
13588                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13589                if ignore_indent {
13590                    full_comment_prefixes = full_comment_prefixes
13591                        .into_iter()
13592                        .map(|s| Arc::from(s.trim_end()))
13593                        .collect();
13594                }
13595
13596                if !full_comment_prefixes.is_empty() {
13597                    let first_prefix = full_comment_prefixes
13598                        .first()
13599                        .expect("prefixes is non-empty");
13600                    let prefix_trimmed_lengths = full_comment_prefixes
13601                        .iter()
13602                        .map(|p| p.trim_end_matches(' ').len())
13603                        .collect::<SmallVec<[usize; 4]>>();
13604
13605                    let mut all_selection_lines_are_comments = true;
13606
13607                    for row in start_row.0..=end_row.0 {
13608                        let row = MultiBufferRow(row);
13609                        if start_row < end_row && snapshot.is_line_blank(row) {
13610                            continue;
13611                        }
13612
13613                        let prefix_range = full_comment_prefixes
13614                            .iter()
13615                            .zip(prefix_trimmed_lengths.iter().copied())
13616                            .map(|(prefix, trimmed_prefix_len)| {
13617                                comment_prefix_range(
13618                                    snapshot.deref(),
13619                                    row,
13620                                    &prefix[..trimmed_prefix_len],
13621                                    &prefix[trimmed_prefix_len..],
13622                                    ignore_indent,
13623                                )
13624                            })
13625                            .max_by_key(|range| range.end.column - range.start.column)
13626                            .expect("prefixes is non-empty");
13627
13628                        if prefix_range.is_empty() {
13629                            all_selection_lines_are_comments = false;
13630                        }
13631
13632                        selection_edit_ranges.push(prefix_range);
13633                    }
13634
13635                    if all_selection_lines_are_comments {
13636                        edits.extend(
13637                            selection_edit_ranges
13638                                .iter()
13639                                .cloned()
13640                                .map(|range| (range, empty_str.clone())),
13641                        );
13642                    } else {
13643                        let min_column = selection_edit_ranges
13644                            .iter()
13645                            .map(|range| range.start.column)
13646                            .min()
13647                            .unwrap_or(0);
13648                        edits.extend(selection_edit_ranges.iter().map(|range| {
13649                            let position = Point::new(range.start.row, min_column);
13650                            (position..position, first_prefix.clone())
13651                        }));
13652                    }
13653                } else if let Some((full_comment_prefix, comment_suffix)) =
13654                    language.block_comment_delimiters()
13655                {
13656                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13657                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13658                    let prefix_range = comment_prefix_range(
13659                        snapshot.deref(),
13660                        start_row,
13661                        comment_prefix,
13662                        comment_prefix_whitespace,
13663                        ignore_indent,
13664                    );
13665                    let suffix_range = comment_suffix_range(
13666                        snapshot.deref(),
13667                        end_row,
13668                        comment_suffix.trim_start_matches(' '),
13669                        comment_suffix.starts_with(' '),
13670                    );
13671
13672                    if prefix_range.is_empty() || suffix_range.is_empty() {
13673                        edits.push((
13674                            prefix_range.start..prefix_range.start,
13675                            full_comment_prefix.clone(),
13676                        ));
13677                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13678                        suffixes_inserted.push((end_row, comment_suffix.len()));
13679                    } else {
13680                        edits.push((prefix_range, empty_str.clone()));
13681                        edits.push((suffix_range, empty_str.clone()));
13682                    }
13683                } else {
13684                    continue;
13685                }
13686            }
13687
13688            drop(snapshot);
13689            this.buffer.update(cx, |buffer, cx| {
13690                buffer.edit(edits, None, cx);
13691            });
13692
13693            // Adjust selections so that they end before any comment suffixes that
13694            // were inserted.
13695            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13696            let mut selections = this.selections.all::<Point>(cx);
13697            let snapshot = this.buffer.read(cx).read(cx);
13698            for selection in &mut selections {
13699                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13700                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13701                        Ordering::Less => {
13702                            suffixes_inserted.next();
13703                            continue;
13704                        }
13705                        Ordering::Greater => break,
13706                        Ordering::Equal => {
13707                            if selection.end.column == snapshot.line_len(row) {
13708                                if selection.is_empty() {
13709                                    selection.start.column -= suffix_len as u32;
13710                                }
13711                                selection.end.column -= suffix_len as u32;
13712                            }
13713                            break;
13714                        }
13715                    }
13716                }
13717            }
13718
13719            drop(snapshot);
13720            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13721                s.select(selections)
13722            });
13723
13724            let selections = this.selections.all::<Point>(cx);
13725            let selections_on_single_row = selections.windows(2).all(|selections| {
13726                selections[0].start.row == selections[1].start.row
13727                    && selections[0].end.row == selections[1].end.row
13728                    && selections[0].start.row == selections[0].end.row
13729            });
13730            let selections_selecting = selections
13731                .iter()
13732                .any(|selection| selection.start != selection.end);
13733            let advance_downwards = action.advance_downwards
13734                && selections_on_single_row
13735                && !selections_selecting
13736                && !matches!(this.mode, EditorMode::SingleLine { .. });
13737
13738            if advance_downwards {
13739                let snapshot = this.buffer.read(cx).snapshot(cx);
13740
13741                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13742                    s.move_cursors_with(|display_snapshot, display_point, _| {
13743                        let mut point = display_point.to_point(display_snapshot);
13744                        point.row += 1;
13745                        point = snapshot.clip_point(point, Bias::Left);
13746                        let display_point = point.to_display_point(display_snapshot);
13747                        let goal = SelectionGoal::HorizontalPosition(
13748                            display_snapshot
13749                                .x_for_display_point(display_point, text_layout_details)
13750                                .into(),
13751                        );
13752                        (display_point, goal)
13753                    })
13754                });
13755            }
13756        });
13757    }
13758
13759    pub fn select_enclosing_symbol(
13760        &mut self,
13761        _: &SelectEnclosingSymbol,
13762        window: &mut Window,
13763        cx: &mut Context<Self>,
13764    ) {
13765        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13766
13767        let buffer = self.buffer.read(cx).snapshot(cx);
13768        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13769
13770        fn update_selection(
13771            selection: &Selection<usize>,
13772            buffer_snap: &MultiBufferSnapshot,
13773        ) -> Option<Selection<usize>> {
13774            let cursor = selection.head();
13775            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13776            for symbol in symbols.iter().rev() {
13777                let start = symbol.range.start.to_offset(buffer_snap);
13778                let end = symbol.range.end.to_offset(buffer_snap);
13779                let new_range = start..end;
13780                if start < selection.start || end > selection.end {
13781                    return Some(Selection {
13782                        id: selection.id,
13783                        start: new_range.start,
13784                        end: new_range.end,
13785                        goal: SelectionGoal::None,
13786                        reversed: selection.reversed,
13787                    });
13788                }
13789            }
13790            None
13791        }
13792
13793        let mut selected_larger_symbol = false;
13794        let new_selections = old_selections
13795            .iter()
13796            .map(|selection| match update_selection(selection, &buffer) {
13797                Some(new_selection) => {
13798                    if new_selection.range() != selection.range() {
13799                        selected_larger_symbol = true;
13800                    }
13801                    new_selection
13802                }
13803                None => selection.clone(),
13804            })
13805            .collect::<Vec<_>>();
13806
13807        if selected_larger_symbol {
13808            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13809                s.select(new_selections);
13810            });
13811        }
13812    }
13813
13814    pub fn select_larger_syntax_node(
13815        &mut self,
13816        _: &SelectLargerSyntaxNode,
13817        window: &mut Window,
13818        cx: &mut Context<Self>,
13819    ) {
13820        let Some(visible_row_count) = self.visible_row_count() else {
13821            return;
13822        };
13823        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13824        if old_selections.is_empty() {
13825            return;
13826        }
13827
13828        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13829
13830        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13831        let buffer = self.buffer.read(cx).snapshot(cx);
13832
13833        let mut selected_larger_node = false;
13834        let mut new_selections = old_selections
13835            .iter()
13836            .map(|selection| {
13837                let old_range = selection.start..selection.end;
13838
13839                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13840                    // manually select word at selection
13841                    if ["string_content", "inline"].contains(&node.kind()) {
13842                        let word_range = {
13843                            let display_point = buffer
13844                                .offset_to_point(old_range.start)
13845                                .to_display_point(&display_map);
13846                            let Range { start, end } =
13847                                movement::surrounding_word(&display_map, display_point);
13848                            start.to_point(&display_map).to_offset(&buffer)
13849                                ..end.to_point(&display_map).to_offset(&buffer)
13850                        };
13851                        // ignore if word is already selected
13852                        if !word_range.is_empty() && old_range != word_range {
13853                            let last_word_range = {
13854                                let display_point = buffer
13855                                    .offset_to_point(old_range.end)
13856                                    .to_display_point(&display_map);
13857                                let Range { start, end } =
13858                                    movement::surrounding_word(&display_map, display_point);
13859                                start.to_point(&display_map).to_offset(&buffer)
13860                                    ..end.to_point(&display_map).to_offset(&buffer)
13861                            };
13862                            // only select word if start and end point belongs to same word
13863                            if word_range == last_word_range {
13864                                selected_larger_node = true;
13865                                return Selection {
13866                                    id: selection.id,
13867                                    start: word_range.start,
13868                                    end: word_range.end,
13869                                    goal: SelectionGoal::None,
13870                                    reversed: selection.reversed,
13871                                };
13872                            }
13873                        }
13874                    }
13875                }
13876
13877                let mut new_range = old_range.clone();
13878                while let Some((_node, containing_range)) =
13879                    buffer.syntax_ancestor(new_range.clone())
13880                {
13881                    new_range = match containing_range {
13882                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13883                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13884                    };
13885                    if !display_map.intersects_fold(new_range.start)
13886                        && !display_map.intersects_fold(new_range.end)
13887                    {
13888                        break;
13889                    }
13890                }
13891
13892                selected_larger_node |= new_range != old_range;
13893                Selection {
13894                    id: selection.id,
13895                    start: new_range.start,
13896                    end: new_range.end,
13897                    goal: SelectionGoal::None,
13898                    reversed: selection.reversed,
13899                }
13900            })
13901            .collect::<Vec<_>>();
13902
13903        if !selected_larger_node {
13904            return; // don't put this call in the history
13905        }
13906
13907        // scroll based on transformation done to the last selection created by the user
13908        let (last_old, last_new) = old_selections
13909            .last()
13910            .zip(new_selections.last().cloned())
13911            .expect("old_selections isn't empty");
13912
13913        // revert selection
13914        let is_selection_reversed = {
13915            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13916            new_selections.last_mut().expect("checked above").reversed =
13917                should_newest_selection_be_reversed;
13918            should_newest_selection_be_reversed
13919        };
13920
13921        if selected_larger_node {
13922            self.select_syntax_node_history.disable_clearing = true;
13923            self.change_selections(None, window, cx, |s| {
13924                s.select(new_selections.clone());
13925            });
13926            self.select_syntax_node_history.disable_clearing = false;
13927        }
13928
13929        let start_row = last_new.start.to_display_point(&display_map).row().0;
13930        let end_row = last_new.end.to_display_point(&display_map).row().0;
13931        let selection_height = end_row - start_row + 1;
13932        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13933
13934        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13935        let scroll_behavior = if fits_on_the_screen {
13936            self.request_autoscroll(Autoscroll::fit(), cx);
13937            SelectSyntaxNodeScrollBehavior::FitSelection
13938        } else if is_selection_reversed {
13939            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13940            SelectSyntaxNodeScrollBehavior::CursorTop
13941        } else {
13942            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13943            SelectSyntaxNodeScrollBehavior::CursorBottom
13944        };
13945
13946        self.select_syntax_node_history.push((
13947            old_selections,
13948            scroll_behavior,
13949            is_selection_reversed,
13950        ));
13951    }
13952
13953    pub fn select_smaller_syntax_node(
13954        &mut self,
13955        _: &SelectSmallerSyntaxNode,
13956        window: &mut Window,
13957        cx: &mut Context<Self>,
13958    ) {
13959        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13960
13961        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13962            self.select_syntax_node_history.pop()
13963        {
13964            if let Some(selection) = selections.last_mut() {
13965                selection.reversed = is_selection_reversed;
13966            }
13967
13968            self.select_syntax_node_history.disable_clearing = true;
13969            self.change_selections(None, window, cx, |s| {
13970                s.select(selections.to_vec());
13971            });
13972            self.select_syntax_node_history.disable_clearing = false;
13973
13974            match scroll_behavior {
13975                SelectSyntaxNodeScrollBehavior::CursorTop => {
13976                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13977                }
13978                SelectSyntaxNodeScrollBehavior::FitSelection => {
13979                    self.request_autoscroll(Autoscroll::fit(), cx);
13980                }
13981                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13982                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13983                }
13984            }
13985        }
13986    }
13987
13988    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13989        if !EditorSettings::get_global(cx).gutter.runnables {
13990            self.clear_tasks();
13991            return Task::ready(());
13992        }
13993        let project = self.project.as_ref().map(Entity::downgrade);
13994        let task_sources = self.lsp_task_sources(cx);
13995        let multi_buffer = self.buffer.downgrade();
13996        cx.spawn_in(window, async move |editor, cx| {
13997            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13998            let Some(project) = project.and_then(|p| p.upgrade()) else {
13999                return;
14000            };
14001            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14002                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14003            }) else {
14004                return;
14005            };
14006
14007            let hide_runnables = project
14008                .update(cx, |project, cx| {
14009                    // Do not display any test indicators in non-dev server remote projects.
14010                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14011                })
14012                .unwrap_or(true);
14013            if hide_runnables {
14014                return;
14015            }
14016            let new_rows =
14017                cx.background_spawn({
14018                    let snapshot = display_snapshot.clone();
14019                    async move {
14020                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14021                    }
14022                })
14023                    .await;
14024            let Ok(lsp_tasks) =
14025                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14026            else {
14027                return;
14028            };
14029            let lsp_tasks = lsp_tasks.await;
14030
14031            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14032                lsp_tasks
14033                    .into_iter()
14034                    .flat_map(|(kind, tasks)| {
14035                        tasks.into_iter().filter_map(move |(location, task)| {
14036                            Some((kind.clone(), location?, task))
14037                        })
14038                    })
14039                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14040                        let buffer = location.target.buffer;
14041                        let buffer_snapshot = buffer.read(cx).snapshot();
14042                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14043                            |(excerpt_id, snapshot, _)| {
14044                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14045                                    display_snapshot
14046                                        .buffer_snapshot
14047                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14048                                } else {
14049                                    None
14050                                }
14051                            },
14052                        );
14053                        if let Some(offset) = offset {
14054                            let task_buffer_range =
14055                                location.target.range.to_point(&buffer_snapshot);
14056                            let context_buffer_range =
14057                                task_buffer_range.to_offset(&buffer_snapshot);
14058                            let context_range = BufferOffset(context_buffer_range.start)
14059                                ..BufferOffset(context_buffer_range.end);
14060
14061                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14062                                .or_insert_with(|| RunnableTasks {
14063                                    templates: Vec::new(),
14064                                    offset,
14065                                    column: task_buffer_range.start.column,
14066                                    extra_variables: HashMap::default(),
14067                                    context_range,
14068                                })
14069                                .templates
14070                                .push((kind, task.original_task().clone()));
14071                        }
14072
14073                        acc
14074                    })
14075            }) else {
14076                return;
14077            };
14078
14079            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14080                buffer.language_settings(cx).tasks.prefer_lsp
14081            }) else {
14082                return;
14083            };
14084
14085            let rows = Self::runnable_rows(
14086                project,
14087                display_snapshot,
14088                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14089                new_rows,
14090                cx.clone(),
14091            )
14092            .await;
14093            editor
14094                .update(cx, |editor, _| {
14095                    editor.clear_tasks();
14096                    for (key, mut value) in rows {
14097                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14098                            value.templates.extend(lsp_tasks.templates);
14099                        }
14100
14101                        editor.insert_tasks(key, value);
14102                    }
14103                    for (key, value) in lsp_tasks_by_rows {
14104                        editor.insert_tasks(key, value);
14105                    }
14106                })
14107                .ok();
14108        })
14109    }
14110    fn fetch_runnable_ranges(
14111        snapshot: &DisplaySnapshot,
14112        range: Range<Anchor>,
14113    ) -> Vec<language::RunnableRange> {
14114        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14115    }
14116
14117    fn runnable_rows(
14118        project: Entity<Project>,
14119        snapshot: DisplaySnapshot,
14120        prefer_lsp: bool,
14121        runnable_ranges: Vec<RunnableRange>,
14122        cx: AsyncWindowContext,
14123    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14124        cx.spawn(async move |cx| {
14125            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14126            for mut runnable in runnable_ranges {
14127                let Some(tasks) = cx
14128                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14129                    .ok()
14130                else {
14131                    continue;
14132                };
14133                let mut tasks = tasks.await;
14134
14135                if prefer_lsp {
14136                    tasks.retain(|(task_kind, _)| {
14137                        !matches!(task_kind, TaskSourceKind::Language { .. })
14138                    });
14139                }
14140                if tasks.is_empty() {
14141                    continue;
14142                }
14143
14144                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14145                let Some(row) = snapshot
14146                    .buffer_snapshot
14147                    .buffer_line_for_row(MultiBufferRow(point.row))
14148                    .map(|(_, range)| range.start.row)
14149                else {
14150                    continue;
14151                };
14152
14153                let context_range =
14154                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14155                runnable_rows.push((
14156                    (runnable.buffer_id, row),
14157                    RunnableTasks {
14158                        templates: tasks,
14159                        offset: snapshot
14160                            .buffer_snapshot
14161                            .anchor_before(runnable.run_range.start),
14162                        context_range,
14163                        column: point.column,
14164                        extra_variables: runnable.extra_captures,
14165                    },
14166                ));
14167            }
14168            runnable_rows
14169        })
14170    }
14171
14172    fn templates_with_tags(
14173        project: &Entity<Project>,
14174        runnable: &mut Runnable,
14175        cx: &mut App,
14176    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14177        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14178            let (worktree_id, file) = project
14179                .buffer_for_id(runnable.buffer, cx)
14180                .and_then(|buffer| buffer.read(cx).file())
14181                .map(|file| (file.worktree_id(cx), file.clone()))
14182                .unzip();
14183
14184            (
14185                project.task_store().read(cx).task_inventory().cloned(),
14186                worktree_id,
14187                file,
14188            )
14189        });
14190
14191        let tags = mem::take(&mut runnable.tags);
14192        let language = runnable.language.clone();
14193        cx.spawn(async move |cx| {
14194            let mut templates_with_tags = Vec::new();
14195            if let Some(inventory) = inventory {
14196                for RunnableTag(tag) in tags {
14197                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14198                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14199                    }) else {
14200                        return templates_with_tags;
14201                    };
14202                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14203                        move |(_, template)| {
14204                            template.tags.iter().any(|source_tag| source_tag == &tag)
14205                        },
14206                    ));
14207                }
14208            }
14209            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14210
14211            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14212                // Strongest source wins; if we have worktree tag binding, prefer that to
14213                // global and language bindings;
14214                // if we have a global binding, prefer that to language binding.
14215                let first_mismatch = templates_with_tags
14216                    .iter()
14217                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14218                if let Some(index) = first_mismatch {
14219                    templates_with_tags.truncate(index);
14220                }
14221            }
14222
14223            templates_with_tags
14224        })
14225    }
14226
14227    pub fn move_to_enclosing_bracket(
14228        &mut self,
14229        _: &MoveToEnclosingBracket,
14230        window: &mut Window,
14231        cx: &mut Context<Self>,
14232    ) {
14233        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14234        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14235            s.move_offsets_with(|snapshot, selection| {
14236                let Some(enclosing_bracket_ranges) =
14237                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14238                else {
14239                    return;
14240                };
14241
14242                let mut best_length = usize::MAX;
14243                let mut best_inside = false;
14244                let mut best_in_bracket_range = false;
14245                let mut best_destination = None;
14246                for (open, close) in enclosing_bracket_ranges {
14247                    let close = close.to_inclusive();
14248                    let length = close.end() - open.start;
14249                    let inside = selection.start >= open.end && selection.end <= *close.start();
14250                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14251                        || close.contains(&selection.head());
14252
14253                    // If best is next to a bracket and current isn't, skip
14254                    if !in_bracket_range && best_in_bracket_range {
14255                        continue;
14256                    }
14257
14258                    // Prefer smaller lengths unless best is inside and current isn't
14259                    if length > best_length && (best_inside || !inside) {
14260                        continue;
14261                    }
14262
14263                    best_length = length;
14264                    best_inside = inside;
14265                    best_in_bracket_range = in_bracket_range;
14266                    best_destination = Some(
14267                        if close.contains(&selection.start) && close.contains(&selection.end) {
14268                            if inside { open.end } else { open.start }
14269                        } else if inside {
14270                            *close.start()
14271                        } else {
14272                            *close.end()
14273                        },
14274                    );
14275                }
14276
14277                if let Some(destination) = best_destination {
14278                    selection.collapse_to(destination, SelectionGoal::None);
14279                }
14280            })
14281        });
14282    }
14283
14284    pub fn undo_selection(
14285        &mut self,
14286        _: &UndoSelection,
14287        window: &mut Window,
14288        cx: &mut Context<Self>,
14289    ) {
14290        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14291        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14292            self.selection_history.mode = SelectionHistoryMode::Undoing;
14293            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14294                this.end_selection(window, cx);
14295                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14296                    s.select_anchors(entry.selections.to_vec())
14297                });
14298            });
14299            self.selection_history.mode = SelectionHistoryMode::Normal;
14300
14301            self.select_next_state = entry.select_next_state;
14302            self.select_prev_state = entry.select_prev_state;
14303            self.add_selections_state = entry.add_selections_state;
14304        }
14305    }
14306
14307    pub fn redo_selection(
14308        &mut self,
14309        _: &RedoSelection,
14310        window: &mut Window,
14311        cx: &mut Context<Self>,
14312    ) {
14313        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14314        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14315            self.selection_history.mode = SelectionHistoryMode::Redoing;
14316            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14317                this.end_selection(window, cx);
14318                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14319                    s.select_anchors(entry.selections.to_vec())
14320                });
14321            });
14322            self.selection_history.mode = SelectionHistoryMode::Normal;
14323
14324            self.select_next_state = entry.select_next_state;
14325            self.select_prev_state = entry.select_prev_state;
14326            self.add_selections_state = entry.add_selections_state;
14327        }
14328    }
14329
14330    pub fn expand_excerpts(
14331        &mut self,
14332        action: &ExpandExcerpts,
14333        _: &mut Window,
14334        cx: &mut Context<Self>,
14335    ) {
14336        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14337    }
14338
14339    pub fn expand_excerpts_down(
14340        &mut self,
14341        action: &ExpandExcerptsDown,
14342        _: &mut Window,
14343        cx: &mut Context<Self>,
14344    ) {
14345        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14346    }
14347
14348    pub fn expand_excerpts_up(
14349        &mut self,
14350        action: &ExpandExcerptsUp,
14351        _: &mut Window,
14352        cx: &mut Context<Self>,
14353    ) {
14354        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14355    }
14356
14357    pub fn expand_excerpts_for_direction(
14358        &mut self,
14359        lines: u32,
14360        direction: ExpandExcerptDirection,
14361
14362        cx: &mut Context<Self>,
14363    ) {
14364        let selections = self.selections.disjoint_anchors();
14365
14366        let lines = if lines == 0 {
14367            EditorSettings::get_global(cx).expand_excerpt_lines
14368        } else {
14369            lines
14370        };
14371
14372        self.buffer.update(cx, |buffer, cx| {
14373            let snapshot = buffer.snapshot(cx);
14374            let mut excerpt_ids = selections
14375                .iter()
14376                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14377                .collect::<Vec<_>>();
14378            excerpt_ids.sort();
14379            excerpt_ids.dedup();
14380            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14381        })
14382    }
14383
14384    pub fn expand_excerpt(
14385        &mut self,
14386        excerpt: ExcerptId,
14387        direction: ExpandExcerptDirection,
14388        window: &mut Window,
14389        cx: &mut Context<Self>,
14390    ) {
14391        let current_scroll_position = self.scroll_position(cx);
14392        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14393        let mut should_scroll_up = false;
14394
14395        if direction == ExpandExcerptDirection::Down {
14396            let multi_buffer = self.buffer.read(cx);
14397            let snapshot = multi_buffer.snapshot(cx);
14398            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14399                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14400                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14401                        let buffer_snapshot = buffer.read(cx).snapshot();
14402                        let excerpt_end_row =
14403                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14404                        let last_row = buffer_snapshot.max_point().row;
14405                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14406                        should_scroll_up = lines_below >= lines_to_expand;
14407                    }
14408                }
14409            }
14410        }
14411
14412        self.buffer.update(cx, |buffer, cx| {
14413            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14414        });
14415
14416        if should_scroll_up {
14417            let new_scroll_position =
14418                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14419            self.set_scroll_position(new_scroll_position, window, cx);
14420        }
14421    }
14422
14423    pub fn go_to_singleton_buffer_point(
14424        &mut self,
14425        point: Point,
14426        window: &mut Window,
14427        cx: &mut Context<Self>,
14428    ) {
14429        self.go_to_singleton_buffer_range(point..point, window, cx);
14430    }
14431
14432    pub fn go_to_singleton_buffer_range(
14433        &mut self,
14434        range: Range<Point>,
14435        window: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) {
14438        let multibuffer = self.buffer().read(cx);
14439        let Some(buffer) = multibuffer.as_singleton() else {
14440            return;
14441        };
14442        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14443            return;
14444        };
14445        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14446            return;
14447        };
14448        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14449            s.select_anchor_ranges([start..end])
14450        });
14451    }
14452
14453    pub fn go_to_diagnostic(
14454        &mut self,
14455        _: &GoToDiagnostic,
14456        window: &mut Window,
14457        cx: &mut Context<Self>,
14458    ) {
14459        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14460        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14461    }
14462
14463    pub fn go_to_prev_diagnostic(
14464        &mut self,
14465        _: &GoToPreviousDiagnostic,
14466        window: &mut Window,
14467        cx: &mut Context<Self>,
14468    ) {
14469        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14470        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14471    }
14472
14473    pub fn go_to_diagnostic_impl(
14474        &mut self,
14475        direction: Direction,
14476        window: &mut Window,
14477        cx: &mut Context<Self>,
14478    ) {
14479        let buffer = self.buffer.read(cx).snapshot(cx);
14480        let selection = self.selections.newest::<usize>(cx);
14481
14482        let mut active_group_id = None;
14483        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14484            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14485                active_group_id = Some(active_group.group_id);
14486            }
14487        }
14488
14489        fn filtered(
14490            snapshot: EditorSnapshot,
14491            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14492        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14493            diagnostics
14494                .filter(|entry| entry.range.start != entry.range.end)
14495                .filter(|entry| !entry.diagnostic.is_unnecessary)
14496                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14497        }
14498
14499        let snapshot = self.snapshot(window, cx);
14500        let before = filtered(
14501            snapshot.clone(),
14502            buffer
14503                .diagnostics_in_range(0..selection.start)
14504                .filter(|entry| entry.range.start <= selection.start),
14505        );
14506        let after = filtered(
14507            snapshot,
14508            buffer
14509                .diagnostics_in_range(selection.start..buffer.len())
14510                .filter(|entry| entry.range.start >= selection.start),
14511        );
14512
14513        let mut found: Option<DiagnosticEntry<usize>> = None;
14514        if direction == Direction::Prev {
14515            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14516            {
14517                for diagnostic in prev_diagnostics.into_iter().rev() {
14518                    if diagnostic.range.start != selection.start
14519                        || active_group_id
14520                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14521                    {
14522                        found = Some(diagnostic);
14523                        break 'outer;
14524                    }
14525                }
14526            }
14527        } else {
14528            for diagnostic in after.chain(before) {
14529                if diagnostic.range.start != selection.start
14530                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14531                {
14532                    found = Some(diagnostic);
14533                    break;
14534                }
14535            }
14536        }
14537        let Some(next_diagnostic) = found else {
14538            return;
14539        };
14540
14541        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14542            return;
14543        };
14544        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14545            s.select_ranges(vec![
14546                next_diagnostic.range.start..next_diagnostic.range.start,
14547            ])
14548        });
14549        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14550        self.refresh_inline_completion(false, true, window, cx);
14551    }
14552
14553    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14554        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14555        let snapshot = self.snapshot(window, cx);
14556        let selection = self.selections.newest::<Point>(cx);
14557        self.go_to_hunk_before_or_after_position(
14558            &snapshot,
14559            selection.head(),
14560            Direction::Next,
14561            window,
14562            cx,
14563        );
14564    }
14565
14566    pub fn go_to_hunk_before_or_after_position(
14567        &mut self,
14568        snapshot: &EditorSnapshot,
14569        position: Point,
14570        direction: Direction,
14571        window: &mut Window,
14572        cx: &mut Context<Editor>,
14573    ) {
14574        let row = if direction == Direction::Next {
14575            self.hunk_after_position(snapshot, position)
14576                .map(|hunk| hunk.row_range.start)
14577        } else {
14578            self.hunk_before_position(snapshot, position)
14579        };
14580
14581        if let Some(row) = row {
14582            let destination = Point::new(row.0, 0);
14583            let autoscroll = Autoscroll::center();
14584
14585            self.unfold_ranges(&[destination..destination], false, false, cx);
14586            self.change_selections(Some(autoscroll), window, cx, |s| {
14587                s.select_ranges([destination..destination]);
14588            });
14589        }
14590    }
14591
14592    fn hunk_after_position(
14593        &mut self,
14594        snapshot: &EditorSnapshot,
14595        position: Point,
14596    ) -> Option<MultiBufferDiffHunk> {
14597        snapshot
14598            .buffer_snapshot
14599            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14600            .find(|hunk| hunk.row_range.start.0 > position.row)
14601            .or_else(|| {
14602                snapshot
14603                    .buffer_snapshot
14604                    .diff_hunks_in_range(Point::zero()..position)
14605                    .find(|hunk| hunk.row_range.end.0 < position.row)
14606            })
14607    }
14608
14609    fn go_to_prev_hunk(
14610        &mut self,
14611        _: &GoToPreviousHunk,
14612        window: &mut Window,
14613        cx: &mut Context<Self>,
14614    ) {
14615        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14616        let snapshot = self.snapshot(window, cx);
14617        let selection = self.selections.newest::<Point>(cx);
14618        self.go_to_hunk_before_or_after_position(
14619            &snapshot,
14620            selection.head(),
14621            Direction::Prev,
14622            window,
14623            cx,
14624        );
14625    }
14626
14627    fn hunk_before_position(
14628        &mut self,
14629        snapshot: &EditorSnapshot,
14630        position: Point,
14631    ) -> Option<MultiBufferRow> {
14632        snapshot
14633            .buffer_snapshot
14634            .diff_hunk_before(position)
14635            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14636    }
14637
14638    fn go_to_next_change(
14639        &mut self,
14640        _: &GoToNextChange,
14641        window: &mut Window,
14642        cx: &mut Context<Self>,
14643    ) {
14644        if let Some(selections) = self
14645            .change_list
14646            .next_change(1, Direction::Next)
14647            .map(|s| s.to_vec())
14648        {
14649            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14650                let map = s.display_map();
14651                s.select_display_ranges(selections.iter().map(|a| {
14652                    let point = a.to_display_point(&map);
14653                    point..point
14654                }))
14655            })
14656        }
14657    }
14658
14659    fn go_to_previous_change(
14660        &mut self,
14661        _: &GoToPreviousChange,
14662        window: &mut Window,
14663        cx: &mut Context<Self>,
14664    ) {
14665        if let Some(selections) = self
14666            .change_list
14667            .next_change(1, Direction::Prev)
14668            .map(|s| s.to_vec())
14669        {
14670            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14671                let map = s.display_map();
14672                s.select_display_ranges(selections.iter().map(|a| {
14673                    let point = a.to_display_point(&map);
14674                    point..point
14675                }))
14676            })
14677        }
14678    }
14679
14680    fn go_to_line<T: 'static>(
14681        &mut self,
14682        position: Anchor,
14683        highlight_color: Option<Hsla>,
14684        window: &mut Window,
14685        cx: &mut Context<Self>,
14686    ) {
14687        let snapshot = self.snapshot(window, cx).display_snapshot;
14688        let position = position.to_point(&snapshot.buffer_snapshot);
14689        let start = snapshot
14690            .buffer_snapshot
14691            .clip_point(Point::new(position.row, 0), Bias::Left);
14692        let end = start + Point::new(1, 0);
14693        let start = snapshot.buffer_snapshot.anchor_before(start);
14694        let end = snapshot.buffer_snapshot.anchor_before(end);
14695
14696        self.highlight_rows::<T>(
14697            start..end,
14698            highlight_color
14699                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14700            Default::default(),
14701            cx,
14702        );
14703
14704        if self.buffer.read(cx).is_singleton() {
14705            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14706        }
14707    }
14708
14709    pub fn go_to_definition(
14710        &mut self,
14711        _: &GoToDefinition,
14712        window: &mut Window,
14713        cx: &mut Context<Self>,
14714    ) -> Task<Result<Navigated>> {
14715        let definition =
14716            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14717        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14718        cx.spawn_in(window, async move |editor, cx| {
14719            if definition.await? == Navigated::Yes {
14720                return Ok(Navigated::Yes);
14721            }
14722            match fallback_strategy {
14723                GoToDefinitionFallback::None => Ok(Navigated::No),
14724                GoToDefinitionFallback::FindAllReferences => {
14725                    match editor.update_in(cx, |editor, window, cx| {
14726                        editor.find_all_references(&FindAllReferences, window, cx)
14727                    })? {
14728                        Some(references) => references.await,
14729                        None => Ok(Navigated::No),
14730                    }
14731                }
14732            }
14733        })
14734    }
14735
14736    pub fn go_to_declaration(
14737        &mut self,
14738        _: &GoToDeclaration,
14739        window: &mut Window,
14740        cx: &mut Context<Self>,
14741    ) -> Task<Result<Navigated>> {
14742        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14743    }
14744
14745    pub fn go_to_declaration_split(
14746        &mut self,
14747        _: &GoToDeclaration,
14748        window: &mut Window,
14749        cx: &mut Context<Self>,
14750    ) -> Task<Result<Navigated>> {
14751        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14752    }
14753
14754    pub fn go_to_implementation(
14755        &mut self,
14756        _: &GoToImplementation,
14757        window: &mut Window,
14758        cx: &mut Context<Self>,
14759    ) -> Task<Result<Navigated>> {
14760        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14761    }
14762
14763    pub fn go_to_implementation_split(
14764        &mut self,
14765        _: &GoToImplementationSplit,
14766        window: &mut Window,
14767        cx: &mut Context<Self>,
14768    ) -> Task<Result<Navigated>> {
14769        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14770    }
14771
14772    pub fn go_to_type_definition(
14773        &mut self,
14774        _: &GoToTypeDefinition,
14775        window: &mut Window,
14776        cx: &mut Context<Self>,
14777    ) -> Task<Result<Navigated>> {
14778        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14779    }
14780
14781    pub fn go_to_definition_split(
14782        &mut self,
14783        _: &GoToDefinitionSplit,
14784        window: &mut Window,
14785        cx: &mut Context<Self>,
14786    ) -> Task<Result<Navigated>> {
14787        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14788    }
14789
14790    pub fn go_to_type_definition_split(
14791        &mut self,
14792        _: &GoToTypeDefinitionSplit,
14793        window: &mut Window,
14794        cx: &mut Context<Self>,
14795    ) -> Task<Result<Navigated>> {
14796        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14797    }
14798
14799    fn go_to_definition_of_kind(
14800        &mut self,
14801        kind: GotoDefinitionKind,
14802        split: bool,
14803        window: &mut Window,
14804        cx: &mut Context<Self>,
14805    ) -> Task<Result<Navigated>> {
14806        let Some(provider) = self.semantics_provider.clone() else {
14807            return Task::ready(Ok(Navigated::No));
14808        };
14809        let head = self.selections.newest::<usize>(cx).head();
14810        let buffer = self.buffer.read(cx);
14811        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14812            text_anchor
14813        } else {
14814            return Task::ready(Ok(Navigated::No));
14815        };
14816
14817        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14818            return Task::ready(Ok(Navigated::No));
14819        };
14820
14821        cx.spawn_in(window, async move |editor, cx| {
14822            let definitions = definitions.await?;
14823            let navigated = editor
14824                .update_in(cx, |editor, window, cx| {
14825                    editor.navigate_to_hover_links(
14826                        Some(kind),
14827                        definitions
14828                            .into_iter()
14829                            .filter(|location| {
14830                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14831                            })
14832                            .map(HoverLink::Text)
14833                            .collect::<Vec<_>>(),
14834                        split,
14835                        window,
14836                        cx,
14837                    )
14838                })?
14839                .await?;
14840            anyhow::Ok(navigated)
14841        })
14842    }
14843
14844    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14845        let selection = self.selections.newest_anchor();
14846        let head = selection.head();
14847        let tail = selection.tail();
14848
14849        let Some((buffer, start_position)) =
14850            self.buffer.read(cx).text_anchor_for_position(head, cx)
14851        else {
14852            return;
14853        };
14854
14855        let end_position = if head != tail {
14856            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14857                return;
14858            };
14859            Some(pos)
14860        } else {
14861            None
14862        };
14863
14864        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14865            let url = if let Some(end_pos) = end_position {
14866                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14867            } else {
14868                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14869            };
14870
14871            if let Some(url) = url {
14872                editor.update(cx, |_, cx| {
14873                    cx.open_url(&url);
14874                })
14875            } else {
14876                Ok(())
14877            }
14878        });
14879
14880        url_finder.detach();
14881    }
14882
14883    pub fn open_selected_filename(
14884        &mut self,
14885        _: &OpenSelectedFilename,
14886        window: &mut Window,
14887        cx: &mut Context<Self>,
14888    ) {
14889        let Some(workspace) = self.workspace() else {
14890            return;
14891        };
14892
14893        let position = self.selections.newest_anchor().head();
14894
14895        let Some((buffer, buffer_position)) =
14896            self.buffer.read(cx).text_anchor_for_position(position, cx)
14897        else {
14898            return;
14899        };
14900
14901        let project = self.project.clone();
14902
14903        cx.spawn_in(window, async move |_, cx| {
14904            let result = find_file(&buffer, project, buffer_position, cx).await;
14905
14906            if let Some((_, path)) = result {
14907                workspace
14908                    .update_in(cx, |workspace, window, cx| {
14909                        workspace.open_resolved_path(path, window, cx)
14910                    })?
14911                    .await?;
14912            }
14913            anyhow::Ok(())
14914        })
14915        .detach();
14916    }
14917
14918    pub(crate) fn navigate_to_hover_links(
14919        &mut self,
14920        kind: Option<GotoDefinitionKind>,
14921        mut definitions: Vec<HoverLink>,
14922        split: bool,
14923        window: &mut Window,
14924        cx: &mut Context<Editor>,
14925    ) -> Task<Result<Navigated>> {
14926        // If there is one definition, just open it directly
14927        if definitions.len() == 1 {
14928            let definition = definitions.pop().unwrap();
14929
14930            enum TargetTaskResult {
14931                Location(Option<Location>),
14932                AlreadyNavigated,
14933            }
14934
14935            let target_task = match definition {
14936                HoverLink::Text(link) => {
14937                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14938                }
14939                HoverLink::InlayHint(lsp_location, server_id) => {
14940                    let computation =
14941                        self.compute_target_location(lsp_location, server_id, window, cx);
14942                    cx.background_spawn(async move {
14943                        let location = computation.await?;
14944                        Ok(TargetTaskResult::Location(location))
14945                    })
14946                }
14947                HoverLink::Url(url) => {
14948                    cx.open_url(&url);
14949                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14950                }
14951                HoverLink::File(path) => {
14952                    if let Some(workspace) = self.workspace() {
14953                        cx.spawn_in(window, async move |_, cx| {
14954                            workspace
14955                                .update_in(cx, |workspace, window, cx| {
14956                                    workspace.open_resolved_path(path, window, cx)
14957                                })?
14958                                .await
14959                                .map(|_| TargetTaskResult::AlreadyNavigated)
14960                        })
14961                    } else {
14962                        Task::ready(Ok(TargetTaskResult::Location(None)))
14963                    }
14964                }
14965            };
14966            cx.spawn_in(window, async move |editor, cx| {
14967                let target = match target_task.await.context("target resolution task")? {
14968                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14969                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14970                    TargetTaskResult::Location(Some(target)) => target,
14971                };
14972
14973                editor.update_in(cx, |editor, window, cx| {
14974                    let Some(workspace) = editor.workspace() else {
14975                        return Navigated::No;
14976                    };
14977                    let pane = workspace.read(cx).active_pane().clone();
14978
14979                    let range = target.range.to_point(target.buffer.read(cx));
14980                    let range = editor.range_for_match(&range);
14981                    let range = collapse_multiline_range(range);
14982
14983                    if !split
14984                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14985                    {
14986                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14987                    } else {
14988                        window.defer(cx, move |window, cx| {
14989                            let target_editor: Entity<Self> =
14990                                workspace.update(cx, |workspace, cx| {
14991                                    let pane = if split {
14992                                        workspace.adjacent_pane(window, cx)
14993                                    } else {
14994                                        workspace.active_pane().clone()
14995                                    };
14996
14997                                    workspace.open_project_item(
14998                                        pane,
14999                                        target.buffer.clone(),
15000                                        true,
15001                                        true,
15002                                        window,
15003                                        cx,
15004                                    )
15005                                });
15006                            target_editor.update(cx, |target_editor, cx| {
15007                                // When selecting a definition in a different buffer, disable the nav history
15008                                // to avoid creating a history entry at the previous cursor location.
15009                                pane.update(cx, |pane, _| pane.disable_history());
15010                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15011                                pane.update(cx, |pane, _| pane.enable_history());
15012                            });
15013                        });
15014                    }
15015                    Navigated::Yes
15016                })
15017            })
15018        } else if !definitions.is_empty() {
15019            cx.spawn_in(window, async move |editor, cx| {
15020                let (title, location_tasks, workspace) = editor
15021                    .update_in(cx, |editor, window, cx| {
15022                        let tab_kind = match kind {
15023                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15024                            _ => "Definitions",
15025                        };
15026                        let title = definitions
15027                            .iter()
15028                            .find_map(|definition| match definition {
15029                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15030                                    let buffer = origin.buffer.read(cx);
15031                                    format!(
15032                                        "{} for {}",
15033                                        tab_kind,
15034                                        buffer
15035                                            .text_for_range(origin.range.clone())
15036                                            .collect::<String>()
15037                                    )
15038                                }),
15039                                HoverLink::InlayHint(_, _) => None,
15040                                HoverLink::Url(_) => None,
15041                                HoverLink::File(_) => None,
15042                            })
15043                            .unwrap_or(tab_kind.to_string());
15044                        let location_tasks = definitions
15045                            .into_iter()
15046                            .map(|definition| match definition {
15047                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15048                                HoverLink::InlayHint(lsp_location, server_id) => editor
15049                                    .compute_target_location(lsp_location, server_id, window, cx),
15050                                HoverLink::Url(_) => Task::ready(Ok(None)),
15051                                HoverLink::File(_) => Task::ready(Ok(None)),
15052                            })
15053                            .collect::<Vec<_>>();
15054                        (title, location_tasks, editor.workspace().clone())
15055                    })
15056                    .context("location tasks preparation")?;
15057
15058                let locations = future::join_all(location_tasks)
15059                    .await
15060                    .into_iter()
15061                    .filter_map(|location| location.transpose())
15062                    .collect::<Result<_>>()
15063                    .context("location tasks")?;
15064
15065                let Some(workspace) = workspace else {
15066                    return Ok(Navigated::No);
15067                };
15068                let opened = workspace
15069                    .update_in(cx, |workspace, window, cx| {
15070                        Self::open_locations_in_multibuffer(
15071                            workspace,
15072                            locations,
15073                            title,
15074                            split,
15075                            MultibufferSelectionMode::First,
15076                            window,
15077                            cx,
15078                        )
15079                    })
15080                    .ok();
15081
15082                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15083            })
15084        } else {
15085            Task::ready(Ok(Navigated::No))
15086        }
15087    }
15088
15089    fn compute_target_location(
15090        &self,
15091        lsp_location: lsp::Location,
15092        server_id: LanguageServerId,
15093        window: &mut Window,
15094        cx: &mut Context<Self>,
15095    ) -> Task<anyhow::Result<Option<Location>>> {
15096        let Some(project) = self.project.clone() else {
15097            return Task::ready(Ok(None));
15098        };
15099
15100        cx.spawn_in(window, async move |editor, cx| {
15101            let location_task = editor.update(cx, |_, cx| {
15102                project.update(cx, |project, cx| {
15103                    let language_server_name = project
15104                        .language_server_statuses(cx)
15105                        .find(|(id, _)| server_id == *id)
15106                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15107                    language_server_name.map(|language_server_name| {
15108                        project.open_local_buffer_via_lsp(
15109                            lsp_location.uri.clone(),
15110                            server_id,
15111                            language_server_name,
15112                            cx,
15113                        )
15114                    })
15115                })
15116            })?;
15117            let location = match location_task {
15118                Some(task) => Some({
15119                    let target_buffer_handle = task.await.context("open local buffer")?;
15120                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15121                        let target_start = target_buffer
15122                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15123                        let target_end = target_buffer
15124                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15125                        target_buffer.anchor_after(target_start)
15126                            ..target_buffer.anchor_before(target_end)
15127                    })?;
15128                    Location {
15129                        buffer: target_buffer_handle,
15130                        range,
15131                    }
15132                }),
15133                None => None,
15134            };
15135            Ok(location)
15136        })
15137    }
15138
15139    pub fn find_all_references(
15140        &mut self,
15141        _: &FindAllReferences,
15142        window: &mut Window,
15143        cx: &mut Context<Self>,
15144    ) -> Option<Task<Result<Navigated>>> {
15145        let selection = self.selections.newest::<usize>(cx);
15146        let multi_buffer = self.buffer.read(cx);
15147        let head = selection.head();
15148
15149        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15150        let head_anchor = multi_buffer_snapshot.anchor_at(
15151            head,
15152            if head < selection.tail() {
15153                Bias::Right
15154            } else {
15155                Bias::Left
15156            },
15157        );
15158
15159        match self
15160            .find_all_references_task_sources
15161            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15162        {
15163            Ok(_) => {
15164                log::info!(
15165                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15166                );
15167                return None;
15168            }
15169            Err(i) => {
15170                self.find_all_references_task_sources.insert(i, head_anchor);
15171            }
15172        }
15173
15174        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15175        let workspace = self.workspace()?;
15176        let project = workspace.read(cx).project().clone();
15177        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15178        Some(cx.spawn_in(window, async move |editor, cx| {
15179            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15180                if let Ok(i) = editor
15181                    .find_all_references_task_sources
15182                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15183                {
15184                    editor.find_all_references_task_sources.remove(i);
15185                }
15186            });
15187
15188            let locations = references.await?;
15189            if locations.is_empty() {
15190                return anyhow::Ok(Navigated::No);
15191            }
15192
15193            workspace.update_in(cx, |workspace, window, cx| {
15194                let title = locations
15195                    .first()
15196                    .as_ref()
15197                    .map(|location| {
15198                        let buffer = location.buffer.read(cx);
15199                        format!(
15200                            "References to `{}`",
15201                            buffer
15202                                .text_for_range(location.range.clone())
15203                                .collect::<String>()
15204                        )
15205                    })
15206                    .unwrap();
15207                Self::open_locations_in_multibuffer(
15208                    workspace,
15209                    locations,
15210                    title,
15211                    false,
15212                    MultibufferSelectionMode::First,
15213                    window,
15214                    cx,
15215                );
15216                Navigated::Yes
15217            })
15218        }))
15219    }
15220
15221    /// Opens a multibuffer with the given project locations in it
15222    pub fn open_locations_in_multibuffer(
15223        workspace: &mut Workspace,
15224        mut locations: Vec<Location>,
15225        title: String,
15226        split: bool,
15227        multibuffer_selection_mode: MultibufferSelectionMode,
15228        window: &mut Window,
15229        cx: &mut Context<Workspace>,
15230    ) {
15231        // If there are multiple definitions, open them in a multibuffer
15232        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15233        let mut locations = locations.into_iter().peekable();
15234        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15235        let capability = workspace.project().read(cx).capability();
15236
15237        let excerpt_buffer = cx.new(|cx| {
15238            let mut multibuffer = MultiBuffer::new(capability);
15239            while let Some(location) = locations.next() {
15240                let buffer = location.buffer.read(cx);
15241                let mut ranges_for_buffer = Vec::new();
15242                let range = location.range.to_point(buffer);
15243                ranges_for_buffer.push(range.clone());
15244
15245                while let Some(next_location) = locations.peek() {
15246                    if next_location.buffer == location.buffer {
15247                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15248                        locations.next();
15249                    } else {
15250                        break;
15251                    }
15252                }
15253
15254                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15255                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15256                    PathKey::for_buffer(&location.buffer, cx),
15257                    location.buffer.clone(),
15258                    ranges_for_buffer,
15259                    DEFAULT_MULTIBUFFER_CONTEXT,
15260                    cx,
15261                );
15262                ranges.extend(new_ranges)
15263            }
15264
15265            multibuffer.with_title(title)
15266        });
15267
15268        let editor = cx.new(|cx| {
15269            Editor::for_multibuffer(
15270                excerpt_buffer,
15271                Some(workspace.project().clone()),
15272                window,
15273                cx,
15274            )
15275        });
15276        editor.update(cx, |editor, cx| {
15277            match multibuffer_selection_mode {
15278                MultibufferSelectionMode::First => {
15279                    if let Some(first_range) = ranges.first() {
15280                        editor.change_selections(None, window, cx, |selections| {
15281                            selections.clear_disjoint();
15282                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15283                        });
15284                    }
15285                    editor.highlight_background::<Self>(
15286                        &ranges,
15287                        |theme| theme.editor_highlighted_line_background,
15288                        cx,
15289                    );
15290                }
15291                MultibufferSelectionMode::All => {
15292                    editor.change_selections(None, window, cx, |selections| {
15293                        selections.clear_disjoint();
15294                        selections.select_anchor_ranges(ranges);
15295                    });
15296                }
15297            }
15298            editor.register_buffers_with_language_servers(cx);
15299        });
15300
15301        let item = Box::new(editor);
15302        let item_id = item.item_id();
15303
15304        if split {
15305            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15306        } else {
15307            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15308                let (preview_item_id, preview_item_idx) =
15309                    workspace.active_pane().read_with(cx, |pane, _| {
15310                        (pane.preview_item_id(), pane.preview_item_idx())
15311                    });
15312
15313                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15314
15315                if let Some(preview_item_id) = preview_item_id {
15316                    workspace.active_pane().update(cx, |pane, cx| {
15317                        pane.remove_item(preview_item_id, false, false, window, cx);
15318                    });
15319                }
15320            } else {
15321                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15322            }
15323        }
15324        workspace.active_pane().update(cx, |pane, cx| {
15325            pane.set_preview_item_id(Some(item_id), cx);
15326        });
15327    }
15328
15329    pub fn rename(
15330        &mut self,
15331        _: &Rename,
15332        window: &mut Window,
15333        cx: &mut Context<Self>,
15334    ) -> Option<Task<Result<()>>> {
15335        use language::ToOffset as _;
15336
15337        let provider = self.semantics_provider.clone()?;
15338        let selection = self.selections.newest_anchor().clone();
15339        let (cursor_buffer, cursor_buffer_position) = self
15340            .buffer
15341            .read(cx)
15342            .text_anchor_for_position(selection.head(), cx)?;
15343        let (tail_buffer, cursor_buffer_position_end) = self
15344            .buffer
15345            .read(cx)
15346            .text_anchor_for_position(selection.tail(), cx)?;
15347        if tail_buffer != cursor_buffer {
15348            return None;
15349        }
15350
15351        let snapshot = cursor_buffer.read(cx).snapshot();
15352        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15353        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15354        let prepare_rename = provider
15355            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15356            .unwrap_or_else(|| Task::ready(Ok(None)));
15357        drop(snapshot);
15358
15359        Some(cx.spawn_in(window, async move |this, cx| {
15360            let rename_range = if let Some(range) = prepare_rename.await? {
15361                Some(range)
15362            } else {
15363                this.update(cx, |this, cx| {
15364                    let buffer = this.buffer.read(cx).snapshot(cx);
15365                    let mut buffer_highlights = this
15366                        .document_highlights_for_position(selection.head(), &buffer)
15367                        .filter(|highlight| {
15368                            highlight.start.excerpt_id == selection.head().excerpt_id
15369                                && highlight.end.excerpt_id == selection.head().excerpt_id
15370                        });
15371                    buffer_highlights
15372                        .next()
15373                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15374                })?
15375            };
15376            if let Some(rename_range) = rename_range {
15377                this.update_in(cx, |this, window, cx| {
15378                    let snapshot = cursor_buffer.read(cx).snapshot();
15379                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15380                    let cursor_offset_in_rename_range =
15381                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15382                    let cursor_offset_in_rename_range_end =
15383                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15384
15385                    this.take_rename(false, window, cx);
15386                    let buffer = this.buffer.read(cx).read(cx);
15387                    let cursor_offset = selection.head().to_offset(&buffer);
15388                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15389                    let rename_end = rename_start + rename_buffer_range.len();
15390                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15391                    let mut old_highlight_id = None;
15392                    let old_name: Arc<str> = buffer
15393                        .chunks(rename_start..rename_end, true)
15394                        .map(|chunk| {
15395                            if old_highlight_id.is_none() {
15396                                old_highlight_id = chunk.syntax_highlight_id;
15397                            }
15398                            chunk.text
15399                        })
15400                        .collect::<String>()
15401                        .into();
15402
15403                    drop(buffer);
15404
15405                    // Position the selection in the rename editor so that it matches the current selection.
15406                    this.show_local_selections = false;
15407                    let rename_editor = cx.new(|cx| {
15408                        let mut editor = Editor::single_line(window, cx);
15409                        editor.buffer.update(cx, |buffer, cx| {
15410                            buffer.edit([(0..0, old_name.clone())], None, cx)
15411                        });
15412                        let rename_selection_range = match cursor_offset_in_rename_range
15413                            .cmp(&cursor_offset_in_rename_range_end)
15414                        {
15415                            Ordering::Equal => {
15416                                editor.select_all(&SelectAll, window, cx);
15417                                return editor;
15418                            }
15419                            Ordering::Less => {
15420                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15421                            }
15422                            Ordering::Greater => {
15423                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15424                            }
15425                        };
15426                        if rename_selection_range.end > old_name.len() {
15427                            editor.select_all(&SelectAll, window, cx);
15428                        } else {
15429                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15430                                s.select_ranges([rename_selection_range]);
15431                            });
15432                        }
15433                        editor
15434                    });
15435                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15436                        if e == &EditorEvent::Focused {
15437                            cx.emit(EditorEvent::FocusedIn)
15438                        }
15439                    })
15440                    .detach();
15441
15442                    let write_highlights =
15443                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15444                    let read_highlights =
15445                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15446                    let ranges = write_highlights
15447                        .iter()
15448                        .flat_map(|(_, ranges)| ranges.iter())
15449                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15450                        .cloned()
15451                        .collect();
15452
15453                    this.highlight_text::<Rename>(
15454                        ranges,
15455                        HighlightStyle {
15456                            fade_out: Some(0.6),
15457                            ..Default::default()
15458                        },
15459                        cx,
15460                    );
15461                    let rename_focus_handle = rename_editor.focus_handle(cx);
15462                    window.focus(&rename_focus_handle);
15463                    let block_id = this.insert_blocks(
15464                        [BlockProperties {
15465                            style: BlockStyle::Flex,
15466                            placement: BlockPlacement::Below(range.start),
15467                            height: Some(1),
15468                            render: Arc::new({
15469                                let rename_editor = rename_editor.clone();
15470                                move |cx: &mut BlockContext| {
15471                                    let mut text_style = cx.editor_style.text.clone();
15472                                    if let Some(highlight_style) = old_highlight_id
15473                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15474                                    {
15475                                        text_style = text_style.highlight(highlight_style);
15476                                    }
15477                                    div()
15478                                        .block_mouse_except_scroll()
15479                                        .pl(cx.anchor_x)
15480                                        .child(EditorElement::new(
15481                                            &rename_editor,
15482                                            EditorStyle {
15483                                                background: cx.theme().system().transparent,
15484                                                local_player: cx.editor_style.local_player,
15485                                                text: text_style,
15486                                                scrollbar_width: cx.editor_style.scrollbar_width,
15487                                                syntax: cx.editor_style.syntax.clone(),
15488                                                status: cx.editor_style.status.clone(),
15489                                                inlay_hints_style: HighlightStyle {
15490                                                    font_weight: Some(FontWeight::BOLD),
15491                                                    ..make_inlay_hints_style(cx.app)
15492                                                },
15493                                                inline_completion_styles: make_suggestion_styles(
15494                                                    cx.app,
15495                                                ),
15496                                                ..EditorStyle::default()
15497                                            },
15498                                        ))
15499                                        .into_any_element()
15500                                }
15501                            }),
15502                            priority: 0,
15503                            render_in_minimap: true,
15504                        }],
15505                        Some(Autoscroll::fit()),
15506                        cx,
15507                    )[0];
15508                    this.pending_rename = Some(RenameState {
15509                        range,
15510                        old_name,
15511                        editor: rename_editor,
15512                        block_id,
15513                    });
15514                })?;
15515            }
15516
15517            Ok(())
15518        }))
15519    }
15520
15521    pub fn confirm_rename(
15522        &mut self,
15523        _: &ConfirmRename,
15524        window: &mut Window,
15525        cx: &mut Context<Self>,
15526    ) -> Option<Task<Result<()>>> {
15527        let rename = self.take_rename(false, window, cx)?;
15528        let workspace = self.workspace()?.downgrade();
15529        let (buffer, start) = self
15530            .buffer
15531            .read(cx)
15532            .text_anchor_for_position(rename.range.start, cx)?;
15533        let (end_buffer, _) = self
15534            .buffer
15535            .read(cx)
15536            .text_anchor_for_position(rename.range.end, cx)?;
15537        if buffer != end_buffer {
15538            return None;
15539        }
15540
15541        let old_name = rename.old_name;
15542        let new_name = rename.editor.read(cx).text(cx);
15543
15544        let rename = self.semantics_provider.as_ref()?.perform_rename(
15545            &buffer,
15546            start,
15547            new_name.clone(),
15548            cx,
15549        )?;
15550
15551        Some(cx.spawn_in(window, async move |editor, cx| {
15552            let project_transaction = rename.await?;
15553            Self::open_project_transaction(
15554                &editor,
15555                workspace,
15556                project_transaction,
15557                format!("Rename: {}{}", old_name, new_name),
15558                cx,
15559            )
15560            .await?;
15561
15562            editor.update(cx, |editor, cx| {
15563                editor.refresh_document_highlights(cx);
15564            })?;
15565            Ok(())
15566        }))
15567    }
15568
15569    fn take_rename(
15570        &mut self,
15571        moving_cursor: bool,
15572        window: &mut Window,
15573        cx: &mut Context<Self>,
15574    ) -> Option<RenameState> {
15575        let rename = self.pending_rename.take()?;
15576        if rename.editor.focus_handle(cx).is_focused(window) {
15577            window.focus(&self.focus_handle);
15578        }
15579
15580        self.remove_blocks(
15581            [rename.block_id].into_iter().collect(),
15582            Some(Autoscroll::fit()),
15583            cx,
15584        );
15585        self.clear_highlights::<Rename>(cx);
15586        self.show_local_selections = true;
15587
15588        if moving_cursor {
15589            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15590                editor.selections.newest::<usize>(cx).head()
15591            });
15592
15593            // Update the selection to match the position of the selection inside
15594            // the rename editor.
15595            let snapshot = self.buffer.read(cx).read(cx);
15596            let rename_range = rename.range.to_offset(&snapshot);
15597            let cursor_in_editor = snapshot
15598                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15599                .min(rename_range.end);
15600            drop(snapshot);
15601
15602            self.change_selections(None, window, cx, |s| {
15603                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15604            });
15605        } else {
15606            self.refresh_document_highlights(cx);
15607        }
15608
15609        Some(rename)
15610    }
15611
15612    pub fn pending_rename(&self) -> Option<&RenameState> {
15613        self.pending_rename.as_ref()
15614    }
15615
15616    fn format(
15617        &mut self,
15618        _: &Format,
15619        window: &mut Window,
15620        cx: &mut Context<Self>,
15621    ) -> Option<Task<Result<()>>> {
15622        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15623
15624        let project = match &self.project {
15625            Some(project) => project.clone(),
15626            None => return None,
15627        };
15628
15629        Some(self.perform_format(
15630            project,
15631            FormatTrigger::Manual,
15632            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15633            window,
15634            cx,
15635        ))
15636    }
15637
15638    fn format_selections(
15639        &mut self,
15640        _: &FormatSelections,
15641        window: &mut Window,
15642        cx: &mut Context<Self>,
15643    ) -> Option<Task<Result<()>>> {
15644        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15645
15646        let project = match &self.project {
15647            Some(project) => project.clone(),
15648            None => return None,
15649        };
15650
15651        let ranges = self
15652            .selections
15653            .all_adjusted(cx)
15654            .into_iter()
15655            .map(|selection| selection.range())
15656            .collect_vec();
15657
15658        Some(self.perform_format(
15659            project,
15660            FormatTrigger::Manual,
15661            FormatTarget::Ranges(ranges),
15662            window,
15663            cx,
15664        ))
15665    }
15666
15667    fn perform_format(
15668        &mut self,
15669        project: Entity<Project>,
15670        trigger: FormatTrigger,
15671        target: FormatTarget,
15672        window: &mut Window,
15673        cx: &mut Context<Self>,
15674    ) -> Task<Result<()>> {
15675        let buffer = self.buffer.clone();
15676        let (buffers, target) = match target {
15677            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15678            FormatTarget::Ranges(selection_ranges) => {
15679                let multi_buffer = buffer.read(cx);
15680                let snapshot = multi_buffer.read(cx);
15681                let mut buffers = HashSet::default();
15682                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15683                    BTreeMap::new();
15684                for selection_range in selection_ranges {
15685                    for (buffer, buffer_range, _) in
15686                        snapshot.range_to_buffer_ranges(selection_range)
15687                    {
15688                        let buffer_id = buffer.remote_id();
15689                        let start = buffer.anchor_before(buffer_range.start);
15690                        let end = buffer.anchor_after(buffer_range.end);
15691                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15692                        buffer_id_to_ranges
15693                            .entry(buffer_id)
15694                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15695                            .or_insert_with(|| vec![start..end]);
15696                    }
15697                }
15698                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15699            }
15700        };
15701
15702        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15703        let selections_prev = transaction_id_prev
15704            .and_then(|transaction_id_prev| {
15705                // default to selections as they were after the last edit, if we have them,
15706                // instead of how they are now.
15707                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15708                // will take you back to where you made the last edit, instead of staying where you scrolled
15709                self.selection_history
15710                    .transaction(transaction_id_prev)
15711                    .map(|t| t.0.clone())
15712            })
15713            .unwrap_or_else(|| {
15714                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15715                self.selections.disjoint_anchors()
15716            });
15717
15718        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15719        let format = project.update(cx, |project, cx| {
15720            project.format(buffers, target, true, trigger, cx)
15721        });
15722
15723        cx.spawn_in(window, async move |editor, cx| {
15724            let transaction = futures::select_biased! {
15725                transaction = format.log_err().fuse() => transaction,
15726                () = timeout => {
15727                    log::warn!("timed out waiting for formatting");
15728                    None
15729                }
15730            };
15731
15732            buffer
15733                .update(cx, |buffer, cx| {
15734                    if let Some(transaction) = transaction {
15735                        if !buffer.is_singleton() {
15736                            buffer.push_transaction(&transaction.0, cx);
15737                        }
15738                    }
15739                    cx.notify();
15740                })
15741                .ok();
15742
15743            if let Some(transaction_id_now) =
15744                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15745            {
15746                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15747                if has_new_transaction {
15748                    _ = editor.update(cx, |editor, _| {
15749                        editor
15750                            .selection_history
15751                            .insert_transaction(transaction_id_now, selections_prev);
15752                    });
15753                }
15754            }
15755
15756            Ok(())
15757        })
15758    }
15759
15760    fn organize_imports(
15761        &mut self,
15762        _: &OrganizeImports,
15763        window: &mut Window,
15764        cx: &mut Context<Self>,
15765    ) -> Option<Task<Result<()>>> {
15766        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15767        let project = match &self.project {
15768            Some(project) => project.clone(),
15769            None => return None,
15770        };
15771        Some(self.perform_code_action_kind(
15772            project,
15773            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15774            window,
15775            cx,
15776        ))
15777    }
15778
15779    fn perform_code_action_kind(
15780        &mut self,
15781        project: Entity<Project>,
15782        kind: CodeActionKind,
15783        window: &mut Window,
15784        cx: &mut Context<Self>,
15785    ) -> Task<Result<()>> {
15786        let buffer = self.buffer.clone();
15787        let buffers = buffer.read(cx).all_buffers();
15788        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15789        let apply_action = project.update(cx, |project, cx| {
15790            project.apply_code_action_kind(buffers, kind, true, cx)
15791        });
15792        cx.spawn_in(window, async move |_, cx| {
15793            let transaction = futures::select_biased! {
15794                () = timeout => {
15795                    log::warn!("timed out waiting for executing code action");
15796                    None
15797                }
15798                transaction = apply_action.log_err().fuse() => transaction,
15799            };
15800            buffer
15801                .update(cx, |buffer, cx| {
15802                    // check if we need this
15803                    if let Some(transaction) = transaction {
15804                        if !buffer.is_singleton() {
15805                            buffer.push_transaction(&transaction.0, cx);
15806                        }
15807                    }
15808                    cx.notify();
15809                })
15810                .ok();
15811            Ok(())
15812        })
15813    }
15814
15815    fn restart_language_server(
15816        &mut self,
15817        _: &RestartLanguageServer,
15818        _: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) {
15821        if let Some(project) = self.project.clone() {
15822            self.buffer.update(cx, |multi_buffer, cx| {
15823                project.update(cx, |project, cx| {
15824                    project.restart_language_servers_for_buffers(
15825                        multi_buffer.all_buffers().into_iter().collect(),
15826                        cx,
15827                    );
15828                });
15829            })
15830        }
15831    }
15832
15833    fn stop_language_server(
15834        &mut self,
15835        _: &StopLanguageServer,
15836        _: &mut Window,
15837        cx: &mut Context<Self>,
15838    ) {
15839        if let Some(project) = self.project.clone() {
15840            self.buffer.update(cx, |multi_buffer, cx| {
15841                project.update(cx, |project, cx| {
15842                    project.stop_language_servers_for_buffers(
15843                        multi_buffer.all_buffers().into_iter().collect(),
15844                        cx,
15845                    );
15846                    cx.emit(project::Event::RefreshInlayHints);
15847                });
15848            });
15849        }
15850    }
15851
15852    fn cancel_language_server_work(
15853        workspace: &mut Workspace,
15854        _: &actions::CancelLanguageServerWork,
15855        _: &mut Window,
15856        cx: &mut Context<Workspace>,
15857    ) {
15858        let project = workspace.project();
15859        let buffers = workspace
15860            .active_item(cx)
15861            .and_then(|item| item.act_as::<Editor>(cx))
15862            .map_or(HashSet::default(), |editor| {
15863                editor.read(cx).buffer.read(cx).all_buffers()
15864            });
15865        project.update(cx, |project, cx| {
15866            project.cancel_language_server_work_for_buffers(buffers, cx);
15867        });
15868    }
15869
15870    fn show_character_palette(
15871        &mut self,
15872        _: &ShowCharacterPalette,
15873        window: &mut Window,
15874        _: &mut Context<Self>,
15875    ) {
15876        window.show_character_palette();
15877    }
15878
15879    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15880        if self.mode.is_minimap() {
15881            return;
15882        }
15883
15884        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15885            let buffer = self.buffer.read(cx).snapshot(cx);
15886            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15887            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15888            let is_valid = buffer
15889                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15890                .any(|entry| {
15891                    entry.diagnostic.is_primary
15892                        && !entry.range.is_empty()
15893                        && entry.range.start == primary_range_start
15894                        && entry.diagnostic.message == active_diagnostics.active_message
15895                });
15896
15897            if !is_valid {
15898                self.dismiss_diagnostics(cx);
15899            }
15900        }
15901    }
15902
15903    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15904        match &self.active_diagnostics {
15905            ActiveDiagnostic::Group(group) => Some(group),
15906            _ => None,
15907        }
15908    }
15909
15910    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15911        self.dismiss_diagnostics(cx);
15912        self.active_diagnostics = ActiveDiagnostic::All;
15913    }
15914
15915    fn activate_diagnostics(
15916        &mut self,
15917        buffer_id: BufferId,
15918        diagnostic: DiagnosticEntry<usize>,
15919        window: &mut Window,
15920        cx: &mut Context<Self>,
15921    ) {
15922        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15923            return;
15924        }
15925        self.dismiss_diagnostics(cx);
15926        let snapshot = self.snapshot(window, cx);
15927        let buffer = self.buffer.read(cx).snapshot(cx);
15928        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15929            return;
15930        };
15931
15932        let diagnostic_group = buffer
15933            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15934            .collect::<Vec<_>>();
15935
15936        let blocks =
15937            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15938
15939        let blocks = self.display_map.update(cx, |display_map, cx| {
15940            display_map.insert_blocks(blocks, cx).into_iter().collect()
15941        });
15942        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15943            active_range: buffer.anchor_before(diagnostic.range.start)
15944                ..buffer.anchor_after(diagnostic.range.end),
15945            active_message: diagnostic.diagnostic.message.clone(),
15946            group_id: diagnostic.diagnostic.group_id,
15947            blocks,
15948        });
15949        cx.notify();
15950    }
15951
15952    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15953        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15954            return;
15955        };
15956
15957        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15958        if let ActiveDiagnostic::Group(group) = prev {
15959            self.display_map.update(cx, |display_map, cx| {
15960                display_map.remove_blocks(group.blocks, cx);
15961            });
15962            cx.notify();
15963        }
15964    }
15965
15966    /// Disable inline diagnostics rendering for this editor.
15967    pub fn disable_inline_diagnostics(&mut self) {
15968        self.inline_diagnostics_enabled = false;
15969        self.inline_diagnostics_update = Task::ready(());
15970        self.inline_diagnostics.clear();
15971    }
15972
15973    pub fn diagnostics_enabled(&self) -> bool {
15974        self.mode.is_full()
15975    }
15976
15977    pub fn inline_diagnostics_enabled(&self) -> bool {
15978        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15979    }
15980
15981    pub fn show_inline_diagnostics(&self) -> bool {
15982        self.show_inline_diagnostics
15983    }
15984
15985    pub fn toggle_inline_diagnostics(
15986        &mut self,
15987        _: &ToggleInlineDiagnostics,
15988        window: &mut Window,
15989        cx: &mut Context<Editor>,
15990    ) {
15991        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15992        self.refresh_inline_diagnostics(false, window, cx);
15993    }
15994
15995    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15996        self.diagnostics_max_severity = severity;
15997        self.display_map.update(cx, |display_map, _| {
15998            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15999        });
16000    }
16001
16002    pub fn toggle_diagnostics(
16003        &mut self,
16004        _: &ToggleDiagnostics,
16005        window: &mut Window,
16006        cx: &mut Context<Editor>,
16007    ) {
16008        if !self.diagnostics_enabled() {
16009            return;
16010        }
16011
16012        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16013            EditorSettings::get_global(cx)
16014                .diagnostics_max_severity
16015                .filter(|severity| severity != &DiagnosticSeverity::Off)
16016                .unwrap_or(DiagnosticSeverity::Hint)
16017        } else {
16018            DiagnosticSeverity::Off
16019        };
16020        self.set_max_diagnostics_severity(new_severity, cx);
16021        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16022            self.active_diagnostics = ActiveDiagnostic::None;
16023            self.inline_diagnostics_update = Task::ready(());
16024            self.inline_diagnostics.clear();
16025        } else {
16026            self.refresh_inline_diagnostics(false, window, cx);
16027        }
16028
16029        cx.notify();
16030    }
16031
16032    pub fn toggle_minimap(
16033        &mut self,
16034        _: &ToggleMinimap,
16035        window: &mut Window,
16036        cx: &mut Context<Editor>,
16037    ) {
16038        if self.supports_minimap(cx) {
16039            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16040        }
16041    }
16042
16043    fn refresh_inline_diagnostics(
16044        &mut self,
16045        debounce: bool,
16046        window: &mut Window,
16047        cx: &mut Context<Self>,
16048    ) {
16049        let max_severity = ProjectSettings::get_global(cx)
16050            .diagnostics
16051            .inline
16052            .max_severity
16053            .unwrap_or(self.diagnostics_max_severity);
16054
16055        if !self.inline_diagnostics_enabled()
16056            || !self.show_inline_diagnostics
16057            || max_severity == DiagnosticSeverity::Off
16058        {
16059            self.inline_diagnostics_update = Task::ready(());
16060            self.inline_diagnostics.clear();
16061            return;
16062        }
16063
16064        let debounce_ms = ProjectSettings::get_global(cx)
16065            .diagnostics
16066            .inline
16067            .update_debounce_ms;
16068        let debounce = if debounce && debounce_ms > 0 {
16069            Some(Duration::from_millis(debounce_ms))
16070        } else {
16071            None
16072        };
16073        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16074            if let Some(debounce) = debounce {
16075                cx.background_executor().timer(debounce).await;
16076            }
16077            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16078                editor
16079                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16080                    .ok()
16081            }) else {
16082                return;
16083            };
16084
16085            let new_inline_diagnostics = cx
16086                .background_spawn(async move {
16087                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16088                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16089                        let message = diagnostic_entry
16090                            .diagnostic
16091                            .message
16092                            .split_once('\n')
16093                            .map(|(line, _)| line)
16094                            .map(SharedString::new)
16095                            .unwrap_or_else(|| {
16096                                SharedString::from(diagnostic_entry.diagnostic.message)
16097                            });
16098                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16099                        let (Ok(i) | Err(i)) = inline_diagnostics
16100                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16101                        inline_diagnostics.insert(
16102                            i,
16103                            (
16104                                start_anchor,
16105                                InlineDiagnostic {
16106                                    message,
16107                                    group_id: diagnostic_entry.diagnostic.group_id,
16108                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16109                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16110                                    severity: diagnostic_entry.diagnostic.severity,
16111                                },
16112                            ),
16113                        );
16114                    }
16115                    inline_diagnostics
16116                })
16117                .await;
16118
16119            editor
16120                .update(cx, |editor, cx| {
16121                    editor.inline_diagnostics = new_inline_diagnostics;
16122                    cx.notify();
16123                })
16124                .ok();
16125        });
16126    }
16127
16128    fn pull_diagnostics(
16129        &mut self,
16130        buffer_id: Option<BufferId>,
16131        window: &Window,
16132        cx: &mut Context<Self>,
16133    ) -> Option<()> {
16134        if !self.mode().is_full() {
16135            return None;
16136        }
16137        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16138            .diagnostics
16139            .lsp_pull_diagnostics;
16140        if !pull_diagnostics_settings.enabled {
16141            return None;
16142        }
16143        let project = self.project.as_ref()?.downgrade();
16144        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16145        let mut buffers = self.buffer.read(cx).all_buffers();
16146        if let Some(buffer_id) = buffer_id {
16147            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16148        }
16149
16150        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16151            cx.background_executor().timer(debounce).await;
16152
16153            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16154                buffers
16155                    .into_iter()
16156                    .flat_map(|buffer| {
16157                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16158                    })
16159                    .collect::<FuturesUnordered<_>>()
16160            }) else {
16161                return;
16162            };
16163
16164            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16165                match pull_task {
16166                    Ok(()) => {
16167                        if editor
16168                            .update_in(cx, |editor, window, cx| {
16169                                editor.update_diagnostics_state(window, cx);
16170                            })
16171                            .is_err()
16172                        {
16173                            return;
16174                        }
16175                    }
16176                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16177                }
16178            }
16179        });
16180
16181        Some(())
16182    }
16183
16184    pub fn set_selections_from_remote(
16185        &mut self,
16186        selections: Vec<Selection<Anchor>>,
16187        pending_selection: Option<Selection<Anchor>>,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        let old_cursor_position = self.selections.newest_anchor().head();
16192        self.selections.change_with(cx, |s| {
16193            s.select_anchors(selections);
16194            if let Some(pending_selection) = pending_selection {
16195                s.set_pending(pending_selection, SelectMode::Character);
16196            } else {
16197                s.clear_pending();
16198            }
16199        });
16200        self.selections_did_change(
16201            false,
16202            &old_cursor_position,
16203            SelectionEffects::default(),
16204            window,
16205            cx,
16206        );
16207    }
16208
16209    pub fn transact(
16210        &mut self,
16211        window: &mut Window,
16212        cx: &mut Context<Self>,
16213        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16214    ) -> Option<TransactionId> {
16215        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16216            this.start_transaction_at(Instant::now(), window, cx);
16217            update(this, window, cx);
16218            this.end_transaction_at(Instant::now(), cx)
16219        })
16220    }
16221
16222    pub fn start_transaction_at(
16223        &mut self,
16224        now: Instant,
16225        window: &mut Window,
16226        cx: &mut Context<Self>,
16227    ) {
16228        self.end_selection(window, cx);
16229        if let Some(tx_id) = self
16230            .buffer
16231            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16232        {
16233            self.selection_history
16234                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16235            cx.emit(EditorEvent::TransactionBegun {
16236                transaction_id: tx_id,
16237            })
16238        }
16239    }
16240
16241    pub fn end_transaction_at(
16242        &mut self,
16243        now: Instant,
16244        cx: &mut Context<Self>,
16245    ) -> Option<TransactionId> {
16246        if let Some(transaction_id) = self
16247            .buffer
16248            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16249        {
16250            if let Some((_, end_selections)) =
16251                self.selection_history.transaction_mut(transaction_id)
16252            {
16253                *end_selections = Some(self.selections.disjoint_anchors());
16254            } else {
16255                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16256            }
16257
16258            cx.emit(EditorEvent::Edited { transaction_id });
16259            Some(transaction_id)
16260        } else {
16261            None
16262        }
16263    }
16264
16265    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16266        if self.selection_mark_mode {
16267            self.change_selections(None, window, cx, |s| {
16268                s.move_with(|_, sel| {
16269                    sel.collapse_to(sel.head(), SelectionGoal::None);
16270                });
16271            })
16272        }
16273        self.selection_mark_mode = true;
16274        cx.notify();
16275    }
16276
16277    pub fn swap_selection_ends(
16278        &mut self,
16279        _: &actions::SwapSelectionEnds,
16280        window: &mut Window,
16281        cx: &mut Context<Self>,
16282    ) {
16283        self.change_selections(None, window, cx, |s| {
16284            s.move_with(|_, sel| {
16285                if sel.start != sel.end {
16286                    sel.reversed = !sel.reversed
16287                }
16288            });
16289        });
16290        self.request_autoscroll(Autoscroll::newest(), cx);
16291        cx.notify();
16292    }
16293
16294    pub fn toggle_fold(
16295        &mut self,
16296        _: &actions::ToggleFold,
16297        window: &mut Window,
16298        cx: &mut Context<Self>,
16299    ) {
16300        if self.is_singleton(cx) {
16301            let selection = self.selections.newest::<Point>(cx);
16302
16303            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16304            let range = if selection.is_empty() {
16305                let point = selection.head().to_display_point(&display_map);
16306                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16307                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16308                    .to_point(&display_map);
16309                start..end
16310            } else {
16311                selection.range()
16312            };
16313            if display_map.folds_in_range(range).next().is_some() {
16314                self.unfold_lines(&Default::default(), window, cx)
16315            } else {
16316                self.fold(&Default::default(), window, cx)
16317            }
16318        } else {
16319            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16320            let buffer_ids: HashSet<_> = self
16321                .selections
16322                .disjoint_anchor_ranges()
16323                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16324                .collect();
16325
16326            let should_unfold = buffer_ids
16327                .iter()
16328                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16329
16330            for buffer_id in buffer_ids {
16331                if should_unfold {
16332                    self.unfold_buffer(buffer_id, cx);
16333                } else {
16334                    self.fold_buffer(buffer_id, cx);
16335                }
16336            }
16337        }
16338    }
16339
16340    pub fn toggle_fold_recursive(
16341        &mut self,
16342        _: &actions::ToggleFoldRecursive,
16343        window: &mut Window,
16344        cx: &mut Context<Self>,
16345    ) {
16346        let selection = self.selections.newest::<Point>(cx);
16347
16348        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16349        let range = if selection.is_empty() {
16350            let point = selection.head().to_display_point(&display_map);
16351            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16352            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16353                .to_point(&display_map);
16354            start..end
16355        } else {
16356            selection.range()
16357        };
16358        if display_map.folds_in_range(range).next().is_some() {
16359            self.unfold_recursive(&Default::default(), window, cx)
16360        } else {
16361            self.fold_recursive(&Default::default(), window, cx)
16362        }
16363    }
16364
16365    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16366        if self.is_singleton(cx) {
16367            let mut to_fold = Vec::new();
16368            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16369            let selections = self.selections.all_adjusted(cx);
16370
16371            for selection in selections {
16372                let range = selection.range().sorted();
16373                let buffer_start_row = range.start.row;
16374
16375                if range.start.row != range.end.row {
16376                    let mut found = false;
16377                    let mut row = range.start.row;
16378                    while row <= range.end.row {
16379                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16380                        {
16381                            found = true;
16382                            row = crease.range().end.row + 1;
16383                            to_fold.push(crease);
16384                        } else {
16385                            row += 1
16386                        }
16387                    }
16388                    if found {
16389                        continue;
16390                    }
16391                }
16392
16393                for row in (0..=range.start.row).rev() {
16394                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16395                        if crease.range().end.row >= buffer_start_row {
16396                            to_fold.push(crease);
16397                            if row <= range.start.row {
16398                                break;
16399                            }
16400                        }
16401                    }
16402                }
16403            }
16404
16405            self.fold_creases(to_fold, true, window, cx);
16406        } else {
16407            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16408            let buffer_ids = self
16409                .selections
16410                .disjoint_anchor_ranges()
16411                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16412                .collect::<HashSet<_>>();
16413            for buffer_id in buffer_ids {
16414                self.fold_buffer(buffer_id, cx);
16415            }
16416        }
16417    }
16418
16419    fn fold_at_level(
16420        &mut self,
16421        fold_at: &FoldAtLevel,
16422        window: &mut Window,
16423        cx: &mut Context<Self>,
16424    ) {
16425        if !self.buffer.read(cx).is_singleton() {
16426            return;
16427        }
16428
16429        let fold_at_level = fold_at.0;
16430        let snapshot = self.buffer.read(cx).snapshot(cx);
16431        let mut to_fold = Vec::new();
16432        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16433
16434        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16435            while start_row < end_row {
16436                match self
16437                    .snapshot(window, cx)
16438                    .crease_for_buffer_row(MultiBufferRow(start_row))
16439                {
16440                    Some(crease) => {
16441                        let nested_start_row = crease.range().start.row + 1;
16442                        let nested_end_row = crease.range().end.row;
16443
16444                        if current_level < fold_at_level {
16445                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16446                        } else if current_level == fold_at_level {
16447                            to_fold.push(crease);
16448                        }
16449
16450                        start_row = nested_end_row + 1;
16451                    }
16452                    None => start_row += 1,
16453                }
16454            }
16455        }
16456
16457        self.fold_creases(to_fold, true, window, cx);
16458    }
16459
16460    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16461        if self.buffer.read(cx).is_singleton() {
16462            let mut fold_ranges = Vec::new();
16463            let snapshot = self.buffer.read(cx).snapshot(cx);
16464
16465            for row in 0..snapshot.max_row().0 {
16466                if let Some(foldable_range) = self
16467                    .snapshot(window, cx)
16468                    .crease_for_buffer_row(MultiBufferRow(row))
16469                {
16470                    fold_ranges.push(foldable_range);
16471                }
16472            }
16473
16474            self.fold_creases(fold_ranges, true, window, cx);
16475        } else {
16476            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16477                editor
16478                    .update_in(cx, |editor, _, cx| {
16479                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16480                            editor.fold_buffer(buffer_id, cx);
16481                        }
16482                    })
16483                    .ok();
16484            });
16485        }
16486    }
16487
16488    pub fn fold_function_bodies(
16489        &mut self,
16490        _: &actions::FoldFunctionBodies,
16491        window: &mut Window,
16492        cx: &mut Context<Self>,
16493    ) {
16494        let snapshot = self.buffer.read(cx).snapshot(cx);
16495
16496        let ranges = snapshot
16497            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16498            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16499            .collect::<Vec<_>>();
16500
16501        let creases = ranges
16502            .into_iter()
16503            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16504            .collect();
16505
16506        self.fold_creases(creases, true, window, cx);
16507    }
16508
16509    pub fn fold_recursive(
16510        &mut self,
16511        _: &actions::FoldRecursive,
16512        window: &mut Window,
16513        cx: &mut Context<Self>,
16514    ) {
16515        let mut to_fold = Vec::new();
16516        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16517        let selections = self.selections.all_adjusted(cx);
16518
16519        for selection in selections {
16520            let range = selection.range().sorted();
16521            let buffer_start_row = range.start.row;
16522
16523            if range.start.row != range.end.row {
16524                let mut found = false;
16525                for row in range.start.row..=range.end.row {
16526                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16527                        found = true;
16528                        to_fold.push(crease);
16529                    }
16530                }
16531                if found {
16532                    continue;
16533                }
16534            }
16535
16536            for row in (0..=range.start.row).rev() {
16537                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16538                    if crease.range().end.row >= buffer_start_row {
16539                        to_fold.push(crease);
16540                    } else {
16541                        break;
16542                    }
16543                }
16544            }
16545        }
16546
16547        self.fold_creases(to_fold, true, window, cx);
16548    }
16549
16550    pub fn fold_at(
16551        &mut self,
16552        buffer_row: MultiBufferRow,
16553        window: &mut Window,
16554        cx: &mut Context<Self>,
16555    ) {
16556        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16557
16558        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16559            let autoscroll = self
16560                .selections
16561                .all::<Point>(cx)
16562                .iter()
16563                .any(|selection| crease.range().overlaps(&selection.range()));
16564
16565            self.fold_creases(vec![crease], autoscroll, window, cx);
16566        }
16567    }
16568
16569    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16570        if self.is_singleton(cx) {
16571            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16572            let buffer = &display_map.buffer_snapshot;
16573            let selections = self.selections.all::<Point>(cx);
16574            let ranges = selections
16575                .iter()
16576                .map(|s| {
16577                    let range = s.display_range(&display_map).sorted();
16578                    let mut start = range.start.to_point(&display_map);
16579                    let mut end = range.end.to_point(&display_map);
16580                    start.column = 0;
16581                    end.column = buffer.line_len(MultiBufferRow(end.row));
16582                    start..end
16583                })
16584                .collect::<Vec<_>>();
16585
16586            self.unfold_ranges(&ranges, true, true, cx);
16587        } else {
16588            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16589            let buffer_ids = self
16590                .selections
16591                .disjoint_anchor_ranges()
16592                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16593                .collect::<HashSet<_>>();
16594            for buffer_id in buffer_ids {
16595                self.unfold_buffer(buffer_id, cx);
16596            }
16597        }
16598    }
16599
16600    pub fn unfold_recursive(
16601        &mut self,
16602        _: &UnfoldRecursive,
16603        _window: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) {
16606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16607        let selections = self.selections.all::<Point>(cx);
16608        let ranges = selections
16609            .iter()
16610            .map(|s| {
16611                let mut range = s.display_range(&display_map).sorted();
16612                *range.start.column_mut() = 0;
16613                *range.end.column_mut() = display_map.line_len(range.end.row());
16614                let start = range.start.to_point(&display_map);
16615                let end = range.end.to_point(&display_map);
16616                start..end
16617            })
16618            .collect::<Vec<_>>();
16619
16620        self.unfold_ranges(&ranges, true, true, cx);
16621    }
16622
16623    pub fn unfold_at(
16624        &mut self,
16625        buffer_row: MultiBufferRow,
16626        _window: &mut Window,
16627        cx: &mut Context<Self>,
16628    ) {
16629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16630
16631        let intersection_range = Point::new(buffer_row.0, 0)
16632            ..Point::new(
16633                buffer_row.0,
16634                display_map.buffer_snapshot.line_len(buffer_row),
16635            );
16636
16637        let autoscroll = self
16638            .selections
16639            .all::<Point>(cx)
16640            .iter()
16641            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16642
16643        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16644    }
16645
16646    pub fn unfold_all(
16647        &mut self,
16648        _: &actions::UnfoldAll,
16649        _window: &mut Window,
16650        cx: &mut Context<Self>,
16651    ) {
16652        if self.buffer.read(cx).is_singleton() {
16653            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16654            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16655        } else {
16656            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16657                editor
16658                    .update(cx, |editor, cx| {
16659                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16660                            editor.unfold_buffer(buffer_id, cx);
16661                        }
16662                    })
16663                    .ok();
16664            });
16665        }
16666    }
16667
16668    pub fn fold_selected_ranges(
16669        &mut self,
16670        _: &FoldSelectedRanges,
16671        window: &mut Window,
16672        cx: &mut Context<Self>,
16673    ) {
16674        let selections = self.selections.all_adjusted(cx);
16675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16676        let ranges = selections
16677            .into_iter()
16678            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16679            .collect::<Vec<_>>();
16680        self.fold_creases(ranges, true, window, cx);
16681    }
16682
16683    pub fn fold_ranges<T: ToOffset + Clone>(
16684        &mut self,
16685        ranges: Vec<Range<T>>,
16686        auto_scroll: bool,
16687        window: &mut Window,
16688        cx: &mut Context<Self>,
16689    ) {
16690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16691        let ranges = ranges
16692            .into_iter()
16693            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16694            .collect::<Vec<_>>();
16695        self.fold_creases(ranges, auto_scroll, window, cx);
16696    }
16697
16698    pub fn fold_creases<T: ToOffset + Clone>(
16699        &mut self,
16700        creases: Vec<Crease<T>>,
16701        auto_scroll: bool,
16702        _window: &mut Window,
16703        cx: &mut Context<Self>,
16704    ) {
16705        if creases.is_empty() {
16706            return;
16707        }
16708
16709        let mut buffers_affected = HashSet::default();
16710        let multi_buffer = self.buffer().read(cx);
16711        for crease in &creases {
16712            if let Some((_, buffer, _)) =
16713                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16714            {
16715                buffers_affected.insert(buffer.read(cx).remote_id());
16716            };
16717        }
16718
16719        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16720
16721        if auto_scroll {
16722            self.request_autoscroll(Autoscroll::fit(), cx);
16723        }
16724
16725        cx.notify();
16726
16727        self.scrollbar_marker_state.dirty = true;
16728        self.folds_did_change(cx);
16729    }
16730
16731    /// Removes any folds whose ranges intersect any of the given ranges.
16732    pub fn unfold_ranges<T: ToOffset + Clone>(
16733        &mut self,
16734        ranges: &[Range<T>],
16735        inclusive: bool,
16736        auto_scroll: bool,
16737        cx: &mut Context<Self>,
16738    ) {
16739        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16740            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16741        });
16742        self.folds_did_change(cx);
16743    }
16744
16745    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16746        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16747            return;
16748        }
16749        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16750        self.display_map.update(cx, |display_map, cx| {
16751            display_map.fold_buffers([buffer_id], cx)
16752        });
16753        cx.emit(EditorEvent::BufferFoldToggled {
16754            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16755            folded: true,
16756        });
16757        cx.notify();
16758    }
16759
16760    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16761        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16762            return;
16763        }
16764        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16765        self.display_map.update(cx, |display_map, cx| {
16766            display_map.unfold_buffers([buffer_id], cx);
16767        });
16768        cx.emit(EditorEvent::BufferFoldToggled {
16769            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16770            folded: false,
16771        });
16772        cx.notify();
16773    }
16774
16775    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16776        self.display_map.read(cx).is_buffer_folded(buffer)
16777    }
16778
16779    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16780        self.display_map.read(cx).folded_buffers()
16781    }
16782
16783    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16784        self.display_map.update(cx, |display_map, cx| {
16785            display_map.disable_header_for_buffer(buffer_id, cx);
16786        });
16787        cx.notify();
16788    }
16789
16790    /// Removes any folds with the given ranges.
16791    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16792        &mut self,
16793        ranges: &[Range<T>],
16794        type_id: TypeId,
16795        auto_scroll: bool,
16796        cx: &mut Context<Self>,
16797    ) {
16798        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16799            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16800        });
16801        self.folds_did_change(cx);
16802    }
16803
16804    fn remove_folds_with<T: ToOffset + Clone>(
16805        &mut self,
16806        ranges: &[Range<T>],
16807        auto_scroll: bool,
16808        cx: &mut Context<Self>,
16809        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16810    ) {
16811        if ranges.is_empty() {
16812            return;
16813        }
16814
16815        let mut buffers_affected = HashSet::default();
16816        let multi_buffer = self.buffer().read(cx);
16817        for range in ranges {
16818            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16819                buffers_affected.insert(buffer.read(cx).remote_id());
16820            };
16821        }
16822
16823        self.display_map.update(cx, update);
16824
16825        if auto_scroll {
16826            self.request_autoscroll(Autoscroll::fit(), cx);
16827        }
16828
16829        cx.notify();
16830        self.scrollbar_marker_state.dirty = true;
16831        self.active_indent_guides_state.dirty = true;
16832    }
16833
16834    pub fn update_fold_widths(
16835        &mut self,
16836        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16837        cx: &mut Context<Self>,
16838    ) -> bool {
16839        self.display_map
16840            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16841    }
16842
16843    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16844        self.display_map.read(cx).fold_placeholder.clone()
16845    }
16846
16847    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16848        self.buffer.update(cx, |buffer, cx| {
16849            buffer.set_all_diff_hunks_expanded(cx);
16850        });
16851    }
16852
16853    pub fn expand_all_diff_hunks(
16854        &mut self,
16855        _: &ExpandAllDiffHunks,
16856        _window: &mut Window,
16857        cx: &mut Context<Self>,
16858    ) {
16859        self.buffer.update(cx, |buffer, cx| {
16860            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16861        });
16862    }
16863
16864    pub fn toggle_selected_diff_hunks(
16865        &mut self,
16866        _: &ToggleSelectedDiffHunks,
16867        _window: &mut Window,
16868        cx: &mut Context<Self>,
16869    ) {
16870        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16871        self.toggle_diff_hunks_in_ranges(ranges, cx);
16872    }
16873
16874    pub fn diff_hunks_in_ranges<'a>(
16875        &'a self,
16876        ranges: &'a [Range<Anchor>],
16877        buffer: &'a MultiBufferSnapshot,
16878    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16879        ranges.iter().flat_map(move |range| {
16880            let end_excerpt_id = range.end.excerpt_id;
16881            let range = range.to_point(buffer);
16882            let mut peek_end = range.end;
16883            if range.end.row < buffer.max_row().0 {
16884                peek_end = Point::new(range.end.row + 1, 0);
16885            }
16886            buffer
16887                .diff_hunks_in_range(range.start..peek_end)
16888                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16889        })
16890    }
16891
16892    pub fn has_stageable_diff_hunks_in_ranges(
16893        &self,
16894        ranges: &[Range<Anchor>],
16895        snapshot: &MultiBufferSnapshot,
16896    ) -> bool {
16897        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16898        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16899    }
16900
16901    pub fn toggle_staged_selected_diff_hunks(
16902        &mut self,
16903        _: &::git::ToggleStaged,
16904        _: &mut Window,
16905        cx: &mut Context<Self>,
16906    ) {
16907        let snapshot = self.buffer.read(cx).snapshot(cx);
16908        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16909        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16910        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16911    }
16912
16913    pub fn set_render_diff_hunk_controls(
16914        &mut self,
16915        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16916        cx: &mut Context<Self>,
16917    ) {
16918        self.render_diff_hunk_controls = render_diff_hunk_controls;
16919        cx.notify();
16920    }
16921
16922    pub fn stage_and_next(
16923        &mut self,
16924        _: &::git::StageAndNext,
16925        window: &mut Window,
16926        cx: &mut Context<Self>,
16927    ) {
16928        self.do_stage_or_unstage_and_next(true, window, cx);
16929    }
16930
16931    pub fn unstage_and_next(
16932        &mut self,
16933        _: &::git::UnstageAndNext,
16934        window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) {
16937        self.do_stage_or_unstage_and_next(false, window, cx);
16938    }
16939
16940    pub fn stage_or_unstage_diff_hunks(
16941        &mut self,
16942        stage: bool,
16943        ranges: Vec<Range<Anchor>>,
16944        cx: &mut Context<Self>,
16945    ) {
16946        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16947        cx.spawn(async move |this, cx| {
16948            task.await?;
16949            this.update(cx, |this, cx| {
16950                let snapshot = this.buffer.read(cx).snapshot(cx);
16951                let chunk_by = this
16952                    .diff_hunks_in_ranges(&ranges, &snapshot)
16953                    .chunk_by(|hunk| hunk.buffer_id);
16954                for (buffer_id, hunks) in &chunk_by {
16955                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16956                }
16957            })
16958        })
16959        .detach_and_log_err(cx);
16960    }
16961
16962    fn save_buffers_for_ranges_if_needed(
16963        &mut self,
16964        ranges: &[Range<Anchor>],
16965        cx: &mut Context<Editor>,
16966    ) -> Task<Result<()>> {
16967        let multibuffer = self.buffer.read(cx);
16968        let snapshot = multibuffer.read(cx);
16969        let buffer_ids: HashSet<_> = ranges
16970            .iter()
16971            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16972            .collect();
16973        drop(snapshot);
16974
16975        let mut buffers = HashSet::default();
16976        for buffer_id in buffer_ids {
16977            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16978                let buffer = buffer_entity.read(cx);
16979                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16980                {
16981                    buffers.insert(buffer_entity);
16982                }
16983            }
16984        }
16985
16986        if let Some(project) = &self.project {
16987            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16988        } else {
16989            Task::ready(Ok(()))
16990        }
16991    }
16992
16993    fn do_stage_or_unstage_and_next(
16994        &mut self,
16995        stage: bool,
16996        window: &mut Window,
16997        cx: &mut Context<Self>,
16998    ) {
16999        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17000
17001        if ranges.iter().any(|range| range.start != range.end) {
17002            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17003            return;
17004        }
17005
17006        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17007        let snapshot = self.snapshot(window, cx);
17008        let position = self.selections.newest::<Point>(cx).head();
17009        let mut row = snapshot
17010            .buffer_snapshot
17011            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17012            .find(|hunk| hunk.row_range.start.0 > position.row)
17013            .map(|hunk| hunk.row_range.start);
17014
17015        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17016        // Outside of the project diff editor, wrap around to the beginning.
17017        if !all_diff_hunks_expanded {
17018            row = row.or_else(|| {
17019                snapshot
17020                    .buffer_snapshot
17021                    .diff_hunks_in_range(Point::zero()..position)
17022                    .find(|hunk| hunk.row_range.end.0 < position.row)
17023                    .map(|hunk| hunk.row_range.start)
17024            });
17025        }
17026
17027        if let Some(row) = row {
17028            let destination = Point::new(row.0, 0);
17029            let autoscroll = Autoscroll::center();
17030
17031            self.unfold_ranges(&[destination..destination], false, false, cx);
17032            self.change_selections(Some(autoscroll), window, cx, |s| {
17033                s.select_ranges([destination..destination]);
17034            });
17035        }
17036    }
17037
17038    fn do_stage_or_unstage(
17039        &self,
17040        stage: bool,
17041        buffer_id: BufferId,
17042        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17043        cx: &mut App,
17044    ) -> Option<()> {
17045        let project = self.project.as_ref()?;
17046        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17047        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17048        let buffer_snapshot = buffer.read(cx).snapshot();
17049        let file_exists = buffer_snapshot
17050            .file()
17051            .is_some_and(|file| file.disk_state().exists());
17052        diff.update(cx, |diff, cx| {
17053            diff.stage_or_unstage_hunks(
17054                stage,
17055                &hunks
17056                    .map(|hunk| buffer_diff::DiffHunk {
17057                        buffer_range: hunk.buffer_range,
17058                        diff_base_byte_range: hunk.diff_base_byte_range,
17059                        secondary_status: hunk.secondary_status,
17060                        range: Point::zero()..Point::zero(), // unused
17061                    })
17062                    .collect::<Vec<_>>(),
17063                &buffer_snapshot,
17064                file_exists,
17065                cx,
17066            )
17067        });
17068        None
17069    }
17070
17071    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17072        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17073        self.buffer
17074            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17075    }
17076
17077    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17078        self.buffer.update(cx, |buffer, cx| {
17079            let ranges = vec![Anchor::min()..Anchor::max()];
17080            if !buffer.all_diff_hunks_expanded()
17081                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17082            {
17083                buffer.collapse_diff_hunks(ranges, cx);
17084                true
17085            } else {
17086                false
17087            }
17088        })
17089    }
17090
17091    fn toggle_diff_hunks_in_ranges(
17092        &mut self,
17093        ranges: Vec<Range<Anchor>>,
17094        cx: &mut Context<Editor>,
17095    ) {
17096        self.buffer.update(cx, |buffer, cx| {
17097            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17098            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17099        })
17100    }
17101
17102    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17103        self.buffer.update(cx, |buffer, cx| {
17104            let snapshot = buffer.snapshot(cx);
17105            let excerpt_id = range.end.excerpt_id;
17106            let point_range = range.to_point(&snapshot);
17107            let expand = !buffer.single_hunk_is_expanded(range, cx);
17108            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17109        })
17110    }
17111
17112    pub(crate) fn apply_all_diff_hunks(
17113        &mut self,
17114        _: &ApplyAllDiffHunks,
17115        window: &mut Window,
17116        cx: &mut Context<Self>,
17117    ) {
17118        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17119
17120        let buffers = self.buffer.read(cx).all_buffers();
17121        for branch_buffer in buffers {
17122            branch_buffer.update(cx, |branch_buffer, cx| {
17123                branch_buffer.merge_into_base(Vec::new(), cx);
17124            });
17125        }
17126
17127        if let Some(project) = self.project.clone() {
17128            self.save(
17129                SaveOptions {
17130                    format: true,
17131                    autosave: false,
17132                },
17133                project,
17134                window,
17135                cx,
17136            )
17137            .detach_and_log_err(cx);
17138        }
17139    }
17140
17141    pub(crate) fn apply_selected_diff_hunks(
17142        &mut self,
17143        _: &ApplyDiffHunk,
17144        window: &mut Window,
17145        cx: &mut Context<Self>,
17146    ) {
17147        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17148        let snapshot = self.snapshot(window, cx);
17149        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17150        let mut ranges_by_buffer = HashMap::default();
17151        self.transact(window, cx, |editor, _window, cx| {
17152            for hunk in hunks {
17153                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17154                    ranges_by_buffer
17155                        .entry(buffer.clone())
17156                        .or_insert_with(Vec::new)
17157                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17158                }
17159            }
17160
17161            for (buffer, ranges) in ranges_by_buffer {
17162                buffer.update(cx, |buffer, cx| {
17163                    buffer.merge_into_base(ranges, cx);
17164                });
17165            }
17166        });
17167
17168        if let Some(project) = self.project.clone() {
17169            self.save(
17170                SaveOptions {
17171                    format: true,
17172                    autosave: false,
17173                },
17174                project,
17175                window,
17176                cx,
17177            )
17178            .detach_and_log_err(cx);
17179        }
17180    }
17181
17182    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17183        if hovered != self.gutter_hovered {
17184            self.gutter_hovered = hovered;
17185            cx.notify();
17186        }
17187    }
17188
17189    pub fn insert_blocks(
17190        &mut self,
17191        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17192        autoscroll: Option<Autoscroll>,
17193        cx: &mut Context<Self>,
17194    ) -> Vec<CustomBlockId> {
17195        let blocks = self
17196            .display_map
17197            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17198        if let Some(autoscroll) = autoscroll {
17199            self.request_autoscroll(autoscroll, cx);
17200        }
17201        cx.notify();
17202        blocks
17203    }
17204
17205    pub fn resize_blocks(
17206        &mut self,
17207        heights: HashMap<CustomBlockId, u32>,
17208        autoscroll: Option<Autoscroll>,
17209        cx: &mut Context<Self>,
17210    ) {
17211        self.display_map
17212            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17213        if let Some(autoscroll) = autoscroll {
17214            self.request_autoscroll(autoscroll, cx);
17215        }
17216        cx.notify();
17217    }
17218
17219    pub fn replace_blocks(
17220        &mut self,
17221        renderers: HashMap<CustomBlockId, RenderBlock>,
17222        autoscroll: Option<Autoscroll>,
17223        cx: &mut Context<Self>,
17224    ) {
17225        self.display_map
17226            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17227        if let Some(autoscroll) = autoscroll {
17228            self.request_autoscroll(autoscroll, cx);
17229        }
17230        cx.notify();
17231    }
17232
17233    pub fn remove_blocks(
17234        &mut self,
17235        block_ids: HashSet<CustomBlockId>,
17236        autoscroll: Option<Autoscroll>,
17237        cx: &mut Context<Self>,
17238    ) {
17239        self.display_map.update(cx, |display_map, cx| {
17240            display_map.remove_blocks(block_ids, cx)
17241        });
17242        if let Some(autoscroll) = autoscroll {
17243            self.request_autoscroll(autoscroll, cx);
17244        }
17245        cx.notify();
17246    }
17247
17248    pub fn row_for_block(
17249        &self,
17250        block_id: CustomBlockId,
17251        cx: &mut Context<Self>,
17252    ) -> Option<DisplayRow> {
17253        self.display_map
17254            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17255    }
17256
17257    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17258        self.focused_block = Some(focused_block);
17259    }
17260
17261    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17262        self.focused_block.take()
17263    }
17264
17265    pub fn insert_creases(
17266        &mut self,
17267        creases: impl IntoIterator<Item = Crease<Anchor>>,
17268        cx: &mut Context<Self>,
17269    ) -> Vec<CreaseId> {
17270        self.display_map
17271            .update(cx, |map, cx| map.insert_creases(creases, cx))
17272    }
17273
17274    pub fn remove_creases(
17275        &mut self,
17276        ids: impl IntoIterator<Item = CreaseId>,
17277        cx: &mut Context<Self>,
17278    ) -> Vec<(CreaseId, Range<Anchor>)> {
17279        self.display_map
17280            .update(cx, |map, cx| map.remove_creases(ids, cx))
17281    }
17282
17283    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17284        self.display_map
17285            .update(cx, |map, cx| map.snapshot(cx))
17286            .longest_row()
17287    }
17288
17289    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17290        self.display_map
17291            .update(cx, |map, cx| map.snapshot(cx))
17292            .max_point()
17293    }
17294
17295    pub fn text(&self, cx: &App) -> String {
17296        self.buffer.read(cx).read(cx).text()
17297    }
17298
17299    pub fn is_empty(&self, cx: &App) -> bool {
17300        self.buffer.read(cx).read(cx).is_empty()
17301    }
17302
17303    pub fn text_option(&self, cx: &App) -> Option<String> {
17304        let text = self.text(cx);
17305        let text = text.trim();
17306
17307        if text.is_empty() {
17308            return None;
17309        }
17310
17311        Some(text.to_string())
17312    }
17313
17314    pub fn set_text(
17315        &mut self,
17316        text: impl Into<Arc<str>>,
17317        window: &mut Window,
17318        cx: &mut Context<Self>,
17319    ) {
17320        self.transact(window, cx, |this, _, cx| {
17321            this.buffer
17322                .read(cx)
17323                .as_singleton()
17324                .expect("you can only call set_text on editors for singleton buffers")
17325                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17326        });
17327    }
17328
17329    pub fn display_text(&self, cx: &mut App) -> String {
17330        self.display_map
17331            .update(cx, |map, cx| map.snapshot(cx))
17332            .text()
17333    }
17334
17335    fn create_minimap(
17336        &self,
17337        minimap_settings: MinimapSettings,
17338        window: &mut Window,
17339        cx: &mut Context<Self>,
17340    ) -> Option<Entity<Self>> {
17341        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17342            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17343    }
17344
17345    fn initialize_new_minimap(
17346        &self,
17347        minimap_settings: MinimapSettings,
17348        window: &mut Window,
17349        cx: &mut Context<Self>,
17350    ) -> Entity<Self> {
17351        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17352
17353        let mut minimap = Editor::new_internal(
17354            EditorMode::Minimap {
17355                parent: cx.weak_entity(),
17356            },
17357            self.buffer.clone(),
17358            self.project.clone(),
17359            Some(self.display_map.clone()),
17360            window,
17361            cx,
17362        );
17363        minimap.scroll_manager.clone_state(&self.scroll_manager);
17364        minimap.set_text_style_refinement(TextStyleRefinement {
17365            font_size: Some(MINIMAP_FONT_SIZE),
17366            font_weight: Some(MINIMAP_FONT_WEIGHT),
17367            ..Default::default()
17368        });
17369        minimap.update_minimap_configuration(minimap_settings, cx);
17370        cx.new(|_| minimap)
17371    }
17372
17373    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17374        let current_line_highlight = minimap_settings
17375            .current_line_highlight
17376            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17377        self.set_current_line_highlight(Some(current_line_highlight));
17378    }
17379
17380    pub fn minimap(&self) -> Option<&Entity<Self>> {
17381        self.minimap
17382            .as_ref()
17383            .filter(|_| self.minimap_visibility.visible())
17384    }
17385
17386    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17387        let mut wrap_guides = smallvec![];
17388
17389        if self.show_wrap_guides == Some(false) {
17390            return wrap_guides;
17391        }
17392
17393        let settings = self.buffer.read(cx).language_settings(cx);
17394        if settings.show_wrap_guides {
17395            match self.soft_wrap_mode(cx) {
17396                SoftWrap::Column(soft_wrap) => {
17397                    wrap_guides.push((soft_wrap as usize, true));
17398                }
17399                SoftWrap::Bounded(soft_wrap) => {
17400                    wrap_guides.push((soft_wrap as usize, true));
17401                }
17402                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17403            }
17404            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17405        }
17406
17407        wrap_guides
17408    }
17409
17410    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17411        let settings = self.buffer.read(cx).language_settings(cx);
17412        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17413        match mode {
17414            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17415                SoftWrap::None
17416            }
17417            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17418            language_settings::SoftWrap::PreferredLineLength => {
17419                SoftWrap::Column(settings.preferred_line_length)
17420            }
17421            language_settings::SoftWrap::Bounded => {
17422                SoftWrap::Bounded(settings.preferred_line_length)
17423            }
17424        }
17425    }
17426
17427    pub fn set_soft_wrap_mode(
17428        &mut self,
17429        mode: language_settings::SoftWrap,
17430
17431        cx: &mut Context<Self>,
17432    ) {
17433        self.soft_wrap_mode_override = Some(mode);
17434        cx.notify();
17435    }
17436
17437    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17438        self.hard_wrap = hard_wrap;
17439        cx.notify();
17440    }
17441
17442    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17443        self.text_style_refinement = Some(style);
17444    }
17445
17446    /// called by the Element so we know what style we were most recently rendered with.
17447    pub(crate) fn set_style(
17448        &mut self,
17449        style: EditorStyle,
17450        window: &mut Window,
17451        cx: &mut Context<Self>,
17452    ) {
17453        // We intentionally do not inform the display map about the minimap style
17454        // so that wrapping is not recalculated and stays consistent for the editor
17455        // and its linked minimap.
17456        if !self.mode.is_minimap() {
17457            let rem_size = window.rem_size();
17458            self.display_map.update(cx, |map, cx| {
17459                map.set_font(
17460                    style.text.font(),
17461                    style.text.font_size.to_pixels(rem_size),
17462                    cx,
17463                )
17464            });
17465        }
17466        self.style = Some(style);
17467    }
17468
17469    pub fn style(&self) -> Option<&EditorStyle> {
17470        self.style.as_ref()
17471    }
17472
17473    // Called by the element. This method is not designed to be called outside of the editor
17474    // element's layout code because it does not notify when rewrapping is computed synchronously.
17475    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17476        self.display_map
17477            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17478    }
17479
17480    pub fn set_soft_wrap(&mut self) {
17481        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17482    }
17483
17484    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17485        if self.soft_wrap_mode_override.is_some() {
17486            self.soft_wrap_mode_override.take();
17487        } else {
17488            let soft_wrap = match self.soft_wrap_mode(cx) {
17489                SoftWrap::GitDiff => return,
17490                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17491                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17492                    language_settings::SoftWrap::None
17493                }
17494            };
17495            self.soft_wrap_mode_override = Some(soft_wrap);
17496        }
17497        cx.notify();
17498    }
17499
17500    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17501        let Some(workspace) = self.workspace() else {
17502            return;
17503        };
17504        let fs = workspace.read(cx).app_state().fs.clone();
17505        let current_show = TabBarSettings::get_global(cx).show;
17506        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17507            setting.show = Some(!current_show);
17508        });
17509    }
17510
17511    pub fn toggle_indent_guides(
17512        &mut self,
17513        _: &ToggleIndentGuides,
17514        _: &mut Window,
17515        cx: &mut Context<Self>,
17516    ) {
17517        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17518            self.buffer
17519                .read(cx)
17520                .language_settings(cx)
17521                .indent_guides
17522                .enabled
17523        });
17524        self.show_indent_guides = Some(!currently_enabled);
17525        cx.notify();
17526    }
17527
17528    fn should_show_indent_guides(&self) -> Option<bool> {
17529        self.show_indent_guides
17530    }
17531
17532    pub fn toggle_line_numbers(
17533        &mut self,
17534        _: &ToggleLineNumbers,
17535        _: &mut Window,
17536        cx: &mut Context<Self>,
17537    ) {
17538        let mut editor_settings = EditorSettings::get_global(cx).clone();
17539        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17540        EditorSettings::override_global(editor_settings, cx);
17541    }
17542
17543    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17544        if let Some(show_line_numbers) = self.show_line_numbers {
17545            return show_line_numbers;
17546        }
17547        EditorSettings::get_global(cx).gutter.line_numbers
17548    }
17549
17550    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17551        self.use_relative_line_numbers
17552            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17553    }
17554
17555    pub fn toggle_relative_line_numbers(
17556        &mut self,
17557        _: &ToggleRelativeLineNumbers,
17558        _: &mut Window,
17559        cx: &mut Context<Self>,
17560    ) {
17561        let is_relative = self.should_use_relative_line_numbers(cx);
17562        self.set_relative_line_number(Some(!is_relative), cx)
17563    }
17564
17565    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17566        self.use_relative_line_numbers = is_relative;
17567        cx.notify();
17568    }
17569
17570    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17571        self.show_gutter = show_gutter;
17572        cx.notify();
17573    }
17574
17575    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17576        self.show_scrollbars = ScrollbarAxes {
17577            horizontal: show,
17578            vertical: show,
17579        };
17580        cx.notify();
17581    }
17582
17583    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17584        self.show_scrollbars.vertical = show;
17585        cx.notify();
17586    }
17587
17588    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17589        self.show_scrollbars.horizontal = show;
17590        cx.notify();
17591    }
17592
17593    pub fn set_minimap_visibility(
17594        &mut self,
17595        minimap_visibility: MinimapVisibility,
17596        window: &mut Window,
17597        cx: &mut Context<Self>,
17598    ) {
17599        if self.minimap_visibility != minimap_visibility {
17600            if minimap_visibility.visible() && self.minimap.is_none() {
17601                let minimap_settings = EditorSettings::get_global(cx).minimap;
17602                self.minimap =
17603                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17604            }
17605            self.minimap_visibility = minimap_visibility;
17606            cx.notify();
17607        }
17608    }
17609
17610    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17611        self.set_show_scrollbars(false, cx);
17612        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17613    }
17614
17615    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17616        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17617    }
17618
17619    /// Normally the text in full mode and auto height editors is padded on the
17620    /// left side by roughly half a character width for improved hit testing.
17621    ///
17622    /// Use this method to disable this for cases where this is not wanted (e.g.
17623    /// if you want to align the editor text with some other text above or below)
17624    /// or if you want to add this padding to single-line editors.
17625    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17626        self.offset_content = offset_content;
17627        cx.notify();
17628    }
17629
17630    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17631        self.show_line_numbers = Some(show_line_numbers);
17632        cx.notify();
17633    }
17634
17635    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17636        self.disable_expand_excerpt_buttons = true;
17637        cx.notify();
17638    }
17639
17640    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17641        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17642        cx.notify();
17643    }
17644
17645    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17646        self.show_code_actions = Some(show_code_actions);
17647        cx.notify();
17648    }
17649
17650    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17651        self.show_runnables = Some(show_runnables);
17652        cx.notify();
17653    }
17654
17655    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17656        self.show_breakpoints = Some(show_breakpoints);
17657        cx.notify();
17658    }
17659
17660    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17661        if self.display_map.read(cx).masked != masked {
17662            self.display_map.update(cx, |map, _| map.masked = masked);
17663        }
17664        cx.notify()
17665    }
17666
17667    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17668        self.show_wrap_guides = Some(show_wrap_guides);
17669        cx.notify();
17670    }
17671
17672    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17673        self.show_indent_guides = Some(show_indent_guides);
17674        cx.notify();
17675    }
17676
17677    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17678        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17679            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17680                if let Some(dir) = file.abs_path(cx).parent() {
17681                    return Some(dir.to_owned());
17682                }
17683            }
17684
17685            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17686                return Some(project_path.path.to_path_buf());
17687            }
17688        }
17689
17690        None
17691    }
17692
17693    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17694        self.active_excerpt(cx)?
17695            .1
17696            .read(cx)
17697            .file()
17698            .and_then(|f| f.as_local())
17699    }
17700
17701    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17702        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17703            let buffer = buffer.read(cx);
17704            if let Some(project_path) = buffer.project_path(cx) {
17705                let project = self.project.as_ref()?.read(cx);
17706                project.absolute_path(&project_path, cx)
17707            } else {
17708                buffer
17709                    .file()
17710                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17711            }
17712        })
17713    }
17714
17715    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17716        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17717            let project_path = buffer.read(cx).project_path(cx)?;
17718            let project = self.project.as_ref()?.read(cx);
17719            let entry = project.entry_for_path(&project_path, cx)?;
17720            let path = entry.path.to_path_buf();
17721            Some(path)
17722        })
17723    }
17724
17725    pub fn reveal_in_finder(
17726        &mut self,
17727        _: &RevealInFileManager,
17728        _window: &mut Window,
17729        cx: &mut Context<Self>,
17730    ) {
17731        if let Some(target) = self.target_file(cx) {
17732            cx.reveal_path(&target.abs_path(cx));
17733        }
17734    }
17735
17736    pub fn copy_path(
17737        &mut self,
17738        _: &zed_actions::workspace::CopyPath,
17739        _window: &mut Window,
17740        cx: &mut Context<Self>,
17741    ) {
17742        if let Some(path) = self.target_file_abs_path(cx) {
17743            if let Some(path) = path.to_str() {
17744                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17745            }
17746        }
17747    }
17748
17749    pub fn copy_relative_path(
17750        &mut self,
17751        _: &zed_actions::workspace::CopyRelativePath,
17752        _window: &mut Window,
17753        cx: &mut Context<Self>,
17754    ) {
17755        if let Some(path) = self.target_file_path(cx) {
17756            if let Some(path) = path.to_str() {
17757                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17758            }
17759        }
17760    }
17761
17762    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17763        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17764            buffer.read(cx).project_path(cx)
17765        } else {
17766            None
17767        }
17768    }
17769
17770    // Returns true if the editor handled a go-to-line request
17771    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17772        maybe!({
17773            let breakpoint_store = self.breakpoint_store.as_ref()?;
17774
17775            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17776            else {
17777                self.clear_row_highlights::<ActiveDebugLine>();
17778                return None;
17779            };
17780
17781            let position = active_stack_frame.position;
17782            let buffer_id = position.buffer_id?;
17783            let snapshot = self
17784                .project
17785                .as_ref()?
17786                .read(cx)
17787                .buffer_for_id(buffer_id, cx)?
17788                .read(cx)
17789                .snapshot();
17790
17791            let mut handled = false;
17792            for (id, ExcerptRange { context, .. }) in
17793                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17794            {
17795                if context.start.cmp(&position, &snapshot).is_ge()
17796                    || context.end.cmp(&position, &snapshot).is_lt()
17797                {
17798                    continue;
17799                }
17800                let snapshot = self.buffer.read(cx).snapshot(cx);
17801                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17802
17803                handled = true;
17804                self.clear_row_highlights::<ActiveDebugLine>();
17805
17806                self.go_to_line::<ActiveDebugLine>(
17807                    multibuffer_anchor,
17808                    Some(cx.theme().colors().editor_debugger_active_line_background),
17809                    window,
17810                    cx,
17811                );
17812
17813                cx.notify();
17814            }
17815
17816            handled.then_some(())
17817        })
17818        .is_some()
17819    }
17820
17821    pub fn copy_file_name_without_extension(
17822        &mut self,
17823        _: &CopyFileNameWithoutExtension,
17824        _: &mut Window,
17825        cx: &mut Context<Self>,
17826    ) {
17827        if let Some(file) = self.target_file(cx) {
17828            if let Some(file_stem) = file.path().file_stem() {
17829                if let Some(name) = file_stem.to_str() {
17830                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17831                }
17832            }
17833        }
17834    }
17835
17836    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17837        if let Some(file) = self.target_file(cx) {
17838            if let Some(file_name) = file.path().file_name() {
17839                if let Some(name) = file_name.to_str() {
17840                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17841                }
17842            }
17843        }
17844    }
17845
17846    pub fn toggle_git_blame(
17847        &mut self,
17848        _: &::git::Blame,
17849        window: &mut Window,
17850        cx: &mut Context<Self>,
17851    ) {
17852        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17853
17854        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17855            self.start_git_blame(true, window, cx);
17856        }
17857
17858        cx.notify();
17859    }
17860
17861    pub fn toggle_git_blame_inline(
17862        &mut self,
17863        _: &ToggleGitBlameInline,
17864        window: &mut Window,
17865        cx: &mut Context<Self>,
17866    ) {
17867        self.toggle_git_blame_inline_internal(true, window, cx);
17868        cx.notify();
17869    }
17870
17871    pub fn open_git_blame_commit(
17872        &mut self,
17873        _: &OpenGitBlameCommit,
17874        window: &mut Window,
17875        cx: &mut Context<Self>,
17876    ) {
17877        self.open_git_blame_commit_internal(window, cx);
17878    }
17879
17880    fn open_git_blame_commit_internal(
17881        &mut self,
17882        window: &mut Window,
17883        cx: &mut Context<Self>,
17884    ) -> Option<()> {
17885        let blame = self.blame.as_ref()?;
17886        let snapshot = self.snapshot(window, cx);
17887        let cursor = self.selections.newest::<Point>(cx).head();
17888        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17889        let blame_entry = blame
17890            .update(cx, |blame, cx| {
17891                blame
17892                    .blame_for_rows(
17893                        &[RowInfo {
17894                            buffer_id: Some(buffer.remote_id()),
17895                            buffer_row: Some(point.row),
17896                            ..Default::default()
17897                        }],
17898                        cx,
17899                    )
17900                    .next()
17901            })
17902            .flatten()?;
17903        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17904        let repo = blame.read(cx).repository(cx)?;
17905        let workspace = self.workspace()?.downgrade();
17906        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17907        None
17908    }
17909
17910    pub fn git_blame_inline_enabled(&self) -> bool {
17911        self.git_blame_inline_enabled
17912    }
17913
17914    pub fn toggle_selection_menu(
17915        &mut self,
17916        _: &ToggleSelectionMenu,
17917        _: &mut Window,
17918        cx: &mut Context<Self>,
17919    ) {
17920        self.show_selection_menu = self
17921            .show_selection_menu
17922            .map(|show_selections_menu| !show_selections_menu)
17923            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17924
17925        cx.notify();
17926    }
17927
17928    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17929        self.show_selection_menu
17930            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17931    }
17932
17933    fn start_git_blame(
17934        &mut self,
17935        user_triggered: bool,
17936        window: &mut Window,
17937        cx: &mut Context<Self>,
17938    ) {
17939        if let Some(project) = self.project.as_ref() {
17940            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17941                return;
17942            };
17943
17944            if buffer.read(cx).file().is_none() {
17945                return;
17946            }
17947
17948            let focused = self.focus_handle(cx).contains_focused(window, cx);
17949
17950            let project = project.clone();
17951            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17952            self.blame_subscription =
17953                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17954            self.blame = Some(blame);
17955        }
17956    }
17957
17958    fn toggle_git_blame_inline_internal(
17959        &mut self,
17960        user_triggered: bool,
17961        window: &mut Window,
17962        cx: &mut Context<Self>,
17963    ) {
17964        if self.git_blame_inline_enabled {
17965            self.git_blame_inline_enabled = false;
17966            self.show_git_blame_inline = false;
17967            self.show_git_blame_inline_delay_task.take();
17968        } else {
17969            self.git_blame_inline_enabled = true;
17970            self.start_git_blame_inline(user_triggered, window, cx);
17971        }
17972
17973        cx.notify();
17974    }
17975
17976    fn start_git_blame_inline(
17977        &mut self,
17978        user_triggered: bool,
17979        window: &mut Window,
17980        cx: &mut Context<Self>,
17981    ) {
17982        self.start_git_blame(user_triggered, window, cx);
17983
17984        if ProjectSettings::get_global(cx)
17985            .git
17986            .inline_blame_delay()
17987            .is_some()
17988        {
17989            self.start_inline_blame_timer(window, cx);
17990        } else {
17991            self.show_git_blame_inline = true
17992        }
17993    }
17994
17995    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17996        self.blame.as_ref()
17997    }
17998
17999    pub fn show_git_blame_gutter(&self) -> bool {
18000        self.show_git_blame_gutter
18001    }
18002
18003    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18004        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18005    }
18006
18007    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18008        self.show_git_blame_inline
18009            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18010            && !self.newest_selection_head_on_empty_line(cx)
18011            && self.has_blame_entries(cx)
18012    }
18013
18014    fn has_blame_entries(&self, cx: &App) -> bool {
18015        self.blame()
18016            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18017    }
18018
18019    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18020        let cursor_anchor = self.selections.newest_anchor().head();
18021
18022        let snapshot = self.buffer.read(cx).snapshot(cx);
18023        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18024
18025        snapshot.line_len(buffer_row) == 0
18026    }
18027
18028    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18029        let buffer_and_selection = maybe!({
18030            let selection = self.selections.newest::<Point>(cx);
18031            let selection_range = selection.range();
18032
18033            let multi_buffer = self.buffer().read(cx);
18034            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18035            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18036
18037            let (buffer, range, _) = if selection.reversed {
18038                buffer_ranges.first()
18039            } else {
18040                buffer_ranges.last()
18041            }?;
18042
18043            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18044                ..text::ToPoint::to_point(&range.end, &buffer).row;
18045            Some((
18046                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18047                selection,
18048            ))
18049        });
18050
18051        let Some((buffer, selection)) = buffer_and_selection else {
18052            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18053        };
18054
18055        let Some(project) = self.project.as_ref() else {
18056            return Task::ready(Err(anyhow!("editor does not have project")));
18057        };
18058
18059        project.update(cx, |project, cx| {
18060            project.get_permalink_to_line(&buffer, selection, cx)
18061        })
18062    }
18063
18064    pub fn copy_permalink_to_line(
18065        &mut self,
18066        _: &CopyPermalinkToLine,
18067        window: &mut Window,
18068        cx: &mut Context<Self>,
18069    ) {
18070        let permalink_task = self.get_permalink_to_line(cx);
18071        let workspace = self.workspace();
18072
18073        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18074            Ok(permalink) => {
18075                cx.update(|_, cx| {
18076                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18077                })
18078                .ok();
18079            }
18080            Err(err) => {
18081                let message = format!("Failed to copy permalink: {err}");
18082
18083                anyhow::Result::<()>::Err(err).log_err();
18084
18085                if let Some(workspace) = workspace {
18086                    workspace
18087                        .update_in(cx, |workspace, _, cx| {
18088                            struct CopyPermalinkToLine;
18089
18090                            workspace.show_toast(
18091                                Toast::new(
18092                                    NotificationId::unique::<CopyPermalinkToLine>(),
18093                                    message,
18094                                ),
18095                                cx,
18096                            )
18097                        })
18098                        .ok();
18099                }
18100            }
18101        })
18102        .detach();
18103    }
18104
18105    pub fn copy_file_location(
18106        &mut self,
18107        _: &CopyFileLocation,
18108        _: &mut Window,
18109        cx: &mut Context<Self>,
18110    ) {
18111        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18112        if let Some(file) = self.target_file(cx) {
18113            if let Some(path) = file.path().to_str() {
18114                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18115            }
18116        }
18117    }
18118
18119    pub fn open_permalink_to_line(
18120        &mut self,
18121        _: &OpenPermalinkToLine,
18122        window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        let permalink_task = self.get_permalink_to_line(cx);
18126        let workspace = self.workspace();
18127
18128        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18129            Ok(permalink) => {
18130                cx.update(|_, cx| {
18131                    cx.open_url(permalink.as_ref());
18132                })
18133                .ok();
18134            }
18135            Err(err) => {
18136                let message = format!("Failed to open permalink: {err}");
18137
18138                anyhow::Result::<()>::Err(err).log_err();
18139
18140                if let Some(workspace) = workspace {
18141                    workspace
18142                        .update(cx, |workspace, cx| {
18143                            struct OpenPermalinkToLine;
18144
18145                            workspace.show_toast(
18146                                Toast::new(
18147                                    NotificationId::unique::<OpenPermalinkToLine>(),
18148                                    message,
18149                                ),
18150                                cx,
18151                            )
18152                        })
18153                        .ok();
18154                }
18155            }
18156        })
18157        .detach();
18158    }
18159
18160    pub fn insert_uuid_v4(
18161        &mut self,
18162        _: &InsertUuidV4,
18163        window: &mut Window,
18164        cx: &mut Context<Self>,
18165    ) {
18166        self.insert_uuid(UuidVersion::V4, window, cx);
18167    }
18168
18169    pub fn insert_uuid_v7(
18170        &mut self,
18171        _: &InsertUuidV7,
18172        window: &mut Window,
18173        cx: &mut Context<Self>,
18174    ) {
18175        self.insert_uuid(UuidVersion::V7, window, cx);
18176    }
18177
18178    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18179        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18180        self.transact(window, cx, |this, window, cx| {
18181            let edits = this
18182                .selections
18183                .all::<Point>(cx)
18184                .into_iter()
18185                .map(|selection| {
18186                    let uuid = match version {
18187                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18188                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18189                    };
18190
18191                    (selection.range(), uuid.to_string())
18192                });
18193            this.edit(edits, cx);
18194            this.refresh_inline_completion(true, false, window, cx);
18195        });
18196    }
18197
18198    pub fn open_selections_in_multibuffer(
18199        &mut self,
18200        _: &OpenSelectionsInMultibuffer,
18201        window: &mut Window,
18202        cx: &mut Context<Self>,
18203    ) {
18204        let multibuffer = self.buffer.read(cx);
18205
18206        let Some(buffer) = multibuffer.as_singleton() else {
18207            return;
18208        };
18209
18210        let Some(workspace) = self.workspace() else {
18211            return;
18212        };
18213
18214        let locations = self
18215            .selections
18216            .disjoint_anchors()
18217            .iter()
18218            .map(|range| Location {
18219                buffer: buffer.clone(),
18220                range: range.start.text_anchor..range.end.text_anchor,
18221            })
18222            .collect::<Vec<_>>();
18223
18224        let title = multibuffer.title(cx).to_string();
18225
18226        cx.spawn_in(window, async move |_, cx| {
18227            workspace.update_in(cx, |workspace, window, cx| {
18228                Self::open_locations_in_multibuffer(
18229                    workspace,
18230                    locations,
18231                    format!("Selections for '{title}'"),
18232                    false,
18233                    MultibufferSelectionMode::All,
18234                    window,
18235                    cx,
18236                );
18237            })
18238        })
18239        .detach();
18240    }
18241
18242    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18243    /// last highlight added will be used.
18244    ///
18245    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18246    pub fn highlight_rows<T: 'static>(
18247        &mut self,
18248        range: Range<Anchor>,
18249        color: Hsla,
18250        options: RowHighlightOptions,
18251        cx: &mut Context<Self>,
18252    ) {
18253        let snapshot = self.buffer().read(cx).snapshot(cx);
18254        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18255        let ix = row_highlights.binary_search_by(|highlight| {
18256            Ordering::Equal
18257                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18258                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18259        });
18260
18261        if let Err(mut ix) = ix {
18262            let index = post_inc(&mut self.highlight_order);
18263
18264            // If this range intersects with the preceding highlight, then merge it with
18265            // the preceding highlight. Otherwise insert a new highlight.
18266            let mut merged = false;
18267            if ix > 0 {
18268                let prev_highlight = &mut row_highlights[ix - 1];
18269                if prev_highlight
18270                    .range
18271                    .end
18272                    .cmp(&range.start, &snapshot)
18273                    .is_ge()
18274                {
18275                    ix -= 1;
18276                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18277                        prev_highlight.range.end = range.end;
18278                    }
18279                    merged = true;
18280                    prev_highlight.index = index;
18281                    prev_highlight.color = color;
18282                    prev_highlight.options = options;
18283                }
18284            }
18285
18286            if !merged {
18287                row_highlights.insert(
18288                    ix,
18289                    RowHighlight {
18290                        range: range.clone(),
18291                        index,
18292                        color,
18293                        options,
18294                        type_id: TypeId::of::<T>(),
18295                    },
18296                );
18297            }
18298
18299            // If any of the following highlights intersect with this one, merge them.
18300            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18301                let highlight = &row_highlights[ix];
18302                if next_highlight
18303                    .range
18304                    .start
18305                    .cmp(&highlight.range.end, &snapshot)
18306                    .is_le()
18307                {
18308                    if next_highlight
18309                        .range
18310                        .end
18311                        .cmp(&highlight.range.end, &snapshot)
18312                        .is_gt()
18313                    {
18314                        row_highlights[ix].range.end = next_highlight.range.end;
18315                    }
18316                    row_highlights.remove(ix + 1);
18317                } else {
18318                    break;
18319                }
18320            }
18321        }
18322    }
18323
18324    /// Remove any highlighted row ranges of the given type that intersect the
18325    /// given ranges.
18326    pub fn remove_highlighted_rows<T: 'static>(
18327        &mut self,
18328        ranges_to_remove: Vec<Range<Anchor>>,
18329        cx: &mut Context<Self>,
18330    ) {
18331        let snapshot = self.buffer().read(cx).snapshot(cx);
18332        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18333        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18334        row_highlights.retain(|highlight| {
18335            while let Some(range_to_remove) = ranges_to_remove.peek() {
18336                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18337                    Ordering::Less | Ordering::Equal => {
18338                        ranges_to_remove.next();
18339                    }
18340                    Ordering::Greater => {
18341                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18342                            Ordering::Less | Ordering::Equal => {
18343                                return false;
18344                            }
18345                            Ordering::Greater => break,
18346                        }
18347                    }
18348                }
18349            }
18350
18351            true
18352        })
18353    }
18354
18355    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18356    pub fn clear_row_highlights<T: 'static>(&mut self) {
18357        self.highlighted_rows.remove(&TypeId::of::<T>());
18358    }
18359
18360    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18361    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18362        self.highlighted_rows
18363            .get(&TypeId::of::<T>())
18364            .map_or(&[] as &[_], |vec| vec.as_slice())
18365            .iter()
18366            .map(|highlight| (highlight.range.clone(), highlight.color))
18367    }
18368
18369    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18370    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18371    /// Allows to ignore certain kinds of highlights.
18372    pub fn highlighted_display_rows(
18373        &self,
18374        window: &mut Window,
18375        cx: &mut App,
18376    ) -> BTreeMap<DisplayRow, LineHighlight> {
18377        let snapshot = self.snapshot(window, cx);
18378        let mut used_highlight_orders = HashMap::default();
18379        self.highlighted_rows
18380            .iter()
18381            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18382            .fold(
18383                BTreeMap::<DisplayRow, LineHighlight>::new(),
18384                |mut unique_rows, highlight| {
18385                    let start = highlight.range.start.to_display_point(&snapshot);
18386                    let end = highlight.range.end.to_display_point(&snapshot);
18387                    let start_row = start.row().0;
18388                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18389                        && end.column() == 0
18390                    {
18391                        end.row().0.saturating_sub(1)
18392                    } else {
18393                        end.row().0
18394                    };
18395                    for row in start_row..=end_row {
18396                        let used_index =
18397                            used_highlight_orders.entry(row).or_insert(highlight.index);
18398                        if highlight.index >= *used_index {
18399                            *used_index = highlight.index;
18400                            unique_rows.insert(
18401                                DisplayRow(row),
18402                                LineHighlight {
18403                                    include_gutter: highlight.options.include_gutter,
18404                                    border: None,
18405                                    background: highlight.color.into(),
18406                                    type_id: Some(highlight.type_id),
18407                                },
18408                            );
18409                        }
18410                    }
18411                    unique_rows
18412                },
18413            )
18414    }
18415
18416    pub fn highlighted_display_row_for_autoscroll(
18417        &self,
18418        snapshot: &DisplaySnapshot,
18419    ) -> Option<DisplayRow> {
18420        self.highlighted_rows
18421            .values()
18422            .flat_map(|highlighted_rows| highlighted_rows.iter())
18423            .filter_map(|highlight| {
18424                if highlight.options.autoscroll {
18425                    Some(highlight.range.start.to_display_point(snapshot).row())
18426                } else {
18427                    None
18428                }
18429            })
18430            .min()
18431    }
18432
18433    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18434        self.highlight_background::<SearchWithinRange>(
18435            ranges,
18436            |colors| colors.editor_document_highlight_read_background,
18437            cx,
18438        )
18439    }
18440
18441    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18442        self.breadcrumb_header = Some(new_header);
18443    }
18444
18445    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18446        self.clear_background_highlights::<SearchWithinRange>(cx);
18447    }
18448
18449    pub fn highlight_background<T: 'static>(
18450        &mut self,
18451        ranges: &[Range<Anchor>],
18452        color_fetcher: fn(&ThemeColors) -> Hsla,
18453        cx: &mut Context<Self>,
18454    ) {
18455        self.background_highlights
18456            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18457        self.scrollbar_marker_state.dirty = true;
18458        cx.notify();
18459    }
18460
18461    pub fn clear_background_highlights<T: 'static>(
18462        &mut self,
18463        cx: &mut Context<Self>,
18464    ) -> Option<BackgroundHighlight> {
18465        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18466        if !text_highlights.1.is_empty() {
18467            self.scrollbar_marker_state.dirty = true;
18468            cx.notify();
18469        }
18470        Some(text_highlights)
18471    }
18472
18473    pub fn highlight_gutter<T: 'static>(
18474        &mut self,
18475        ranges: impl Into<Vec<Range<Anchor>>>,
18476        color_fetcher: fn(&App) -> Hsla,
18477        cx: &mut Context<Self>,
18478    ) {
18479        self.gutter_highlights
18480            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18481        cx.notify();
18482    }
18483
18484    pub fn clear_gutter_highlights<T: 'static>(
18485        &mut self,
18486        cx: &mut Context<Self>,
18487    ) -> Option<GutterHighlight> {
18488        cx.notify();
18489        self.gutter_highlights.remove(&TypeId::of::<T>())
18490    }
18491
18492    pub fn insert_gutter_highlight<T: 'static>(
18493        &mut self,
18494        range: Range<Anchor>,
18495        color_fetcher: fn(&App) -> Hsla,
18496        cx: &mut Context<Self>,
18497    ) {
18498        let snapshot = self.buffer().read(cx).snapshot(cx);
18499        let mut highlights = self
18500            .gutter_highlights
18501            .remove(&TypeId::of::<T>())
18502            .map(|(_, highlights)| highlights)
18503            .unwrap_or_default();
18504        let ix = highlights.binary_search_by(|highlight| {
18505            Ordering::Equal
18506                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18507                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18508        });
18509        if let Err(ix) = ix {
18510            highlights.insert(ix, range);
18511        }
18512        self.gutter_highlights
18513            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18514    }
18515
18516    pub fn remove_gutter_highlights<T: 'static>(
18517        &mut self,
18518        ranges_to_remove: Vec<Range<Anchor>>,
18519        cx: &mut Context<Self>,
18520    ) {
18521        let snapshot = self.buffer().read(cx).snapshot(cx);
18522        let Some((color_fetcher, mut gutter_highlights)) =
18523            self.gutter_highlights.remove(&TypeId::of::<T>())
18524        else {
18525            return;
18526        };
18527        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18528        gutter_highlights.retain(|highlight| {
18529            while let Some(range_to_remove) = ranges_to_remove.peek() {
18530                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18531                    Ordering::Less | Ordering::Equal => {
18532                        ranges_to_remove.next();
18533                    }
18534                    Ordering::Greater => {
18535                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18536                            Ordering::Less | Ordering::Equal => {
18537                                return false;
18538                            }
18539                            Ordering::Greater => break,
18540                        }
18541                    }
18542                }
18543            }
18544
18545            true
18546        });
18547        self.gutter_highlights
18548            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18549    }
18550
18551    #[cfg(feature = "test-support")]
18552    pub fn all_text_background_highlights(
18553        &self,
18554        window: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18557        let snapshot = self.snapshot(window, cx);
18558        let buffer = &snapshot.buffer_snapshot;
18559        let start = buffer.anchor_before(0);
18560        let end = buffer.anchor_after(buffer.len());
18561        let theme = cx.theme().colors();
18562        self.background_highlights_in_range(start..end, &snapshot, theme)
18563    }
18564
18565    #[cfg(feature = "test-support")]
18566    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18567        let snapshot = self.buffer().read(cx).snapshot(cx);
18568
18569        let highlights = self
18570            .background_highlights
18571            .get(&TypeId::of::<items::BufferSearchHighlights>());
18572
18573        if let Some((_color, ranges)) = highlights {
18574            ranges
18575                .iter()
18576                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18577                .collect_vec()
18578        } else {
18579            vec![]
18580        }
18581    }
18582
18583    fn document_highlights_for_position<'a>(
18584        &'a self,
18585        position: Anchor,
18586        buffer: &'a MultiBufferSnapshot,
18587    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18588        let read_highlights = self
18589            .background_highlights
18590            .get(&TypeId::of::<DocumentHighlightRead>())
18591            .map(|h| &h.1);
18592        let write_highlights = self
18593            .background_highlights
18594            .get(&TypeId::of::<DocumentHighlightWrite>())
18595            .map(|h| &h.1);
18596        let left_position = position.bias_left(buffer);
18597        let right_position = position.bias_right(buffer);
18598        read_highlights
18599            .into_iter()
18600            .chain(write_highlights)
18601            .flat_map(move |ranges| {
18602                let start_ix = match ranges.binary_search_by(|probe| {
18603                    let cmp = probe.end.cmp(&left_position, buffer);
18604                    if cmp.is_ge() {
18605                        Ordering::Greater
18606                    } else {
18607                        Ordering::Less
18608                    }
18609                }) {
18610                    Ok(i) | Err(i) => i,
18611                };
18612
18613                ranges[start_ix..]
18614                    .iter()
18615                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18616            })
18617    }
18618
18619    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18620        self.background_highlights
18621            .get(&TypeId::of::<T>())
18622            .map_or(false, |(_, highlights)| !highlights.is_empty())
18623    }
18624
18625    pub fn background_highlights_in_range(
18626        &self,
18627        search_range: Range<Anchor>,
18628        display_snapshot: &DisplaySnapshot,
18629        theme: &ThemeColors,
18630    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18631        let mut results = Vec::new();
18632        for (color_fetcher, ranges) in self.background_highlights.values() {
18633            let color = color_fetcher(theme);
18634            let start_ix = match ranges.binary_search_by(|probe| {
18635                let cmp = probe
18636                    .end
18637                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18638                if cmp.is_gt() {
18639                    Ordering::Greater
18640                } else {
18641                    Ordering::Less
18642                }
18643            }) {
18644                Ok(i) | Err(i) => i,
18645            };
18646            for range in &ranges[start_ix..] {
18647                if range
18648                    .start
18649                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18650                    .is_ge()
18651                {
18652                    break;
18653                }
18654
18655                let start = range.start.to_display_point(display_snapshot);
18656                let end = range.end.to_display_point(display_snapshot);
18657                results.push((start..end, color))
18658            }
18659        }
18660        results
18661    }
18662
18663    pub fn background_highlight_row_ranges<T: 'static>(
18664        &self,
18665        search_range: Range<Anchor>,
18666        display_snapshot: &DisplaySnapshot,
18667        count: usize,
18668    ) -> Vec<RangeInclusive<DisplayPoint>> {
18669        let mut results = Vec::new();
18670        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18671            return vec![];
18672        };
18673
18674        let start_ix = match ranges.binary_search_by(|probe| {
18675            let cmp = probe
18676                .end
18677                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18678            if cmp.is_gt() {
18679                Ordering::Greater
18680            } else {
18681                Ordering::Less
18682            }
18683        }) {
18684            Ok(i) | Err(i) => i,
18685        };
18686        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18687            if let (Some(start_display), Some(end_display)) = (start, end) {
18688                results.push(
18689                    start_display.to_display_point(display_snapshot)
18690                        ..=end_display.to_display_point(display_snapshot),
18691                );
18692            }
18693        };
18694        let mut start_row: Option<Point> = None;
18695        let mut end_row: Option<Point> = None;
18696        if ranges.len() > count {
18697            return Vec::new();
18698        }
18699        for range in &ranges[start_ix..] {
18700            if range
18701                .start
18702                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18703                .is_ge()
18704            {
18705                break;
18706            }
18707            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18708            if let Some(current_row) = &end_row {
18709                if end.row == current_row.row {
18710                    continue;
18711                }
18712            }
18713            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18714            if start_row.is_none() {
18715                assert_eq!(end_row, None);
18716                start_row = Some(start);
18717                end_row = Some(end);
18718                continue;
18719            }
18720            if let Some(current_end) = end_row.as_mut() {
18721                if start.row > current_end.row + 1 {
18722                    push_region(start_row, end_row);
18723                    start_row = Some(start);
18724                    end_row = Some(end);
18725                } else {
18726                    // Merge two hunks.
18727                    *current_end = end;
18728                }
18729            } else {
18730                unreachable!();
18731            }
18732        }
18733        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18734        push_region(start_row, end_row);
18735        results
18736    }
18737
18738    pub fn gutter_highlights_in_range(
18739        &self,
18740        search_range: Range<Anchor>,
18741        display_snapshot: &DisplaySnapshot,
18742        cx: &App,
18743    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18744        let mut results = Vec::new();
18745        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18746            let color = color_fetcher(cx);
18747            let start_ix = match ranges.binary_search_by(|probe| {
18748                let cmp = probe
18749                    .end
18750                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18751                if cmp.is_gt() {
18752                    Ordering::Greater
18753                } else {
18754                    Ordering::Less
18755                }
18756            }) {
18757                Ok(i) | Err(i) => i,
18758            };
18759            for range in &ranges[start_ix..] {
18760                if range
18761                    .start
18762                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18763                    .is_ge()
18764                {
18765                    break;
18766                }
18767
18768                let start = range.start.to_display_point(display_snapshot);
18769                let end = range.end.to_display_point(display_snapshot);
18770                results.push((start..end, color))
18771            }
18772        }
18773        results
18774    }
18775
18776    /// Get the text ranges corresponding to the redaction query
18777    pub fn redacted_ranges(
18778        &self,
18779        search_range: Range<Anchor>,
18780        display_snapshot: &DisplaySnapshot,
18781        cx: &App,
18782    ) -> Vec<Range<DisplayPoint>> {
18783        display_snapshot
18784            .buffer_snapshot
18785            .redacted_ranges(search_range, |file| {
18786                if let Some(file) = file {
18787                    file.is_private()
18788                        && EditorSettings::get(
18789                            Some(SettingsLocation {
18790                                worktree_id: file.worktree_id(cx),
18791                                path: file.path().as_ref(),
18792                            }),
18793                            cx,
18794                        )
18795                        .redact_private_values
18796                } else {
18797                    false
18798                }
18799            })
18800            .map(|range| {
18801                range.start.to_display_point(display_snapshot)
18802                    ..range.end.to_display_point(display_snapshot)
18803            })
18804            .collect()
18805    }
18806
18807    pub fn highlight_text<T: 'static>(
18808        &mut self,
18809        ranges: Vec<Range<Anchor>>,
18810        style: HighlightStyle,
18811        cx: &mut Context<Self>,
18812    ) {
18813        self.display_map.update(cx, |map, _| {
18814            map.highlight_text(TypeId::of::<T>(), ranges, style)
18815        });
18816        cx.notify();
18817    }
18818
18819    pub(crate) fn highlight_inlays<T: 'static>(
18820        &mut self,
18821        highlights: Vec<InlayHighlight>,
18822        style: HighlightStyle,
18823        cx: &mut Context<Self>,
18824    ) {
18825        self.display_map.update(cx, |map, _| {
18826            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18827        });
18828        cx.notify();
18829    }
18830
18831    pub fn text_highlights<'a, T: 'static>(
18832        &'a self,
18833        cx: &'a App,
18834    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18835        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18836    }
18837
18838    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18839        let cleared = self
18840            .display_map
18841            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18842        if cleared {
18843            cx.notify();
18844        }
18845    }
18846
18847    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18848        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18849            && self.focus_handle.is_focused(window)
18850    }
18851
18852    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18853        self.show_cursor_when_unfocused = is_enabled;
18854        cx.notify();
18855    }
18856
18857    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18858        cx.notify();
18859    }
18860
18861    fn on_debug_session_event(
18862        &mut self,
18863        _session: Entity<Session>,
18864        event: &SessionEvent,
18865        cx: &mut Context<Self>,
18866    ) {
18867        match event {
18868            SessionEvent::InvalidateInlineValue => {
18869                self.refresh_inline_values(cx);
18870            }
18871            _ => {}
18872        }
18873    }
18874
18875    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18876        let Some(project) = self.project.clone() else {
18877            return;
18878        };
18879
18880        if !self.inline_value_cache.enabled {
18881            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18882            self.splice_inlays(&inlays, Vec::new(), cx);
18883            return;
18884        }
18885
18886        let current_execution_position = self
18887            .highlighted_rows
18888            .get(&TypeId::of::<ActiveDebugLine>())
18889            .and_then(|lines| lines.last().map(|line| line.range.start));
18890
18891        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18892            let inline_values = editor
18893                .update(cx, |editor, cx| {
18894                    let Some(current_execution_position) = current_execution_position else {
18895                        return Some(Task::ready(Ok(Vec::new())));
18896                    };
18897
18898                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18899                        let snapshot = buffer.snapshot(cx);
18900
18901                        let excerpt = snapshot.excerpt_containing(
18902                            current_execution_position..current_execution_position,
18903                        )?;
18904
18905                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18906                    })?;
18907
18908                    let range =
18909                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18910
18911                    project.inline_values(buffer, range, cx)
18912                })
18913                .ok()
18914                .flatten()?
18915                .await
18916                .context("refreshing debugger inlays")
18917                .log_err()?;
18918
18919            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18920
18921            for (buffer_id, inline_value) in inline_values
18922                .into_iter()
18923                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18924            {
18925                buffer_inline_values
18926                    .entry(buffer_id)
18927                    .or_default()
18928                    .push(inline_value);
18929            }
18930
18931            editor
18932                .update(cx, |editor, cx| {
18933                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18934                    let mut new_inlays = Vec::default();
18935
18936                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18937                        let buffer_id = buffer_snapshot.remote_id();
18938                        buffer_inline_values
18939                            .get(&buffer_id)
18940                            .into_iter()
18941                            .flatten()
18942                            .for_each(|hint| {
18943                                let inlay = Inlay::debugger_hint(
18944                                    post_inc(&mut editor.next_inlay_id),
18945                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18946                                    hint.text(),
18947                                );
18948
18949                                new_inlays.push(inlay);
18950                            });
18951                    }
18952
18953                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18954                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18955
18956                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18957                })
18958                .ok()?;
18959            Some(())
18960        });
18961    }
18962
18963    fn on_buffer_event(
18964        &mut self,
18965        multibuffer: &Entity<MultiBuffer>,
18966        event: &multi_buffer::Event,
18967        window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        match event {
18971            multi_buffer::Event::Edited {
18972                singleton_buffer_edited,
18973                edited_buffer,
18974            } => {
18975                self.scrollbar_marker_state.dirty = true;
18976                self.active_indent_guides_state.dirty = true;
18977                self.refresh_active_diagnostics(cx);
18978                self.refresh_code_actions(window, cx);
18979                self.refresh_selected_text_highlights(true, window, cx);
18980                refresh_matching_bracket_highlights(self, window, cx);
18981                if self.has_active_inline_completion() {
18982                    self.update_visible_inline_completion(window, cx);
18983                }
18984                if let Some(project) = self.project.as_ref() {
18985                    if let Some(edited_buffer) = edited_buffer {
18986                        project.update(cx, |project, cx| {
18987                            self.registered_buffers
18988                                .entry(edited_buffer.read(cx).remote_id())
18989                                .or_insert_with(|| {
18990                                    project
18991                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18992                                });
18993                        });
18994                        if edited_buffer.read(cx).file().is_some() {
18995                            self.pull_diagnostics(
18996                                Some(edited_buffer.read(cx).remote_id()),
18997                                window,
18998                                cx,
18999                            );
19000                        }
19001                    }
19002                }
19003                cx.emit(EditorEvent::BufferEdited);
19004                cx.emit(SearchEvent::MatchesInvalidated);
19005                if *singleton_buffer_edited {
19006                    if let Some(buffer) = edited_buffer {
19007                        if buffer.read(cx).file().is_none() {
19008                            cx.emit(EditorEvent::TitleChanged);
19009                        }
19010                    }
19011                    if let Some(project) = &self.project {
19012                        #[allow(clippy::mutable_key_type)]
19013                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19014                            multibuffer
19015                                .all_buffers()
19016                                .into_iter()
19017                                .filter_map(|buffer| {
19018                                    buffer.update(cx, |buffer, cx| {
19019                                        let language = buffer.language()?;
19020                                        let should_discard = project.update(cx, |project, cx| {
19021                                            project.is_local()
19022                                                && !project.has_language_servers_for(buffer, cx)
19023                                        });
19024                                        should_discard.not().then_some(language.clone())
19025                                    })
19026                                })
19027                                .collect::<HashSet<_>>()
19028                        });
19029                        if !languages_affected.is_empty() {
19030                            self.refresh_inlay_hints(
19031                                InlayHintRefreshReason::BufferEdited(languages_affected),
19032                                cx,
19033                            );
19034                        }
19035                    }
19036                }
19037
19038                let Some(project) = &self.project else { return };
19039                let (telemetry, is_via_ssh) = {
19040                    let project = project.read(cx);
19041                    let telemetry = project.client().telemetry().clone();
19042                    let is_via_ssh = project.is_via_ssh();
19043                    (telemetry, is_via_ssh)
19044                };
19045                refresh_linked_ranges(self, window, cx);
19046                telemetry.log_edit_event("editor", is_via_ssh);
19047            }
19048            multi_buffer::Event::ExcerptsAdded {
19049                buffer,
19050                predecessor,
19051                excerpts,
19052            } => {
19053                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19054                let buffer_id = buffer.read(cx).remote_id();
19055                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19056                    if let Some(project) = &self.project {
19057                        update_uncommitted_diff_for_buffer(
19058                            cx.entity(),
19059                            project,
19060                            [buffer.clone()],
19061                            self.buffer.clone(),
19062                            cx,
19063                        )
19064                        .detach();
19065                    }
19066                }
19067                cx.emit(EditorEvent::ExcerptsAdded {
19068                    buffer: buffer.clone(),
19069                    predecessor: *predecessor,
19070                    excerpts: excerpts.clone(),
19071                });
19072                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19073            }
19074            multi_buffer::Event::ExcerptsRemoved {
19075                ids,
19076                removed_buffer_ids,
19077            } => {
19078                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19079                let buffer = self.buffer.read(cx);
19080                self.registered_buffers
19081                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19082                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19083                cx.emit(EditorEvent::ExcerptsRemoved {
19084                    ids: ids.clone(),
19085                    removed_buffer_ids: removed_buffer_ids.clone(),
19086                })
19087            }
19088            multi_buffer::Event::ExcerptsEdited {
19089                excerpt_ids,
19090                buffer_ids,
19091            } => {
19092                self.display_map.update(cx, |map, cx| {
19093                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19094                });
19095                cx.emit(EditorEvent::ExcerptsEdited {
19096                    ids: excerpt_ids.clone(),
19097                })
19098            }
19099            multi_buffer::Event::ExcerptsExpanded { ids } => {
19100                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19101                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19102            }
19103            multi_buffer::Event::Reparsed(buffer_id) => {
19104                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19105                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19106
19107                cx.emit(EditorEvent::Reparsed(*buffer_id));
19108            }
19109            multi_buffer::Event::DiffHunksToggled => {
19110                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19111            }
19112            multi_buffer::Event::LanguageChanged(buffer_id) => {
19113                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19114                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19115                cx.emit(EditorEvent::Reparsed(*buffer_id));
19116                cx.notify();
19117            }
19118            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19119            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19120            multi_buffer::Event::FileHandleChanged
19121            | multi_buffer::Event::Reloaded
19122            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19123            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19124            multi_buffer::Event::DiagnosticsUpdated => {
19125                self.update_diagnostics_state(window, cx);
19126            }
19127            _ => {}
19128        };
19129    }
19130
19131    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19132        self.refresh_active_diagnostics(cx);
19133        self.refresh_inline_diagnostics(true, window, cx);
19134        self.scrollbar_marker_state.dirty = true;
19135        cx.notify();
19136    }
19137
19138    pub fn start_temporary_diff_override(&mut self) {
19139        self.load_diff_task.take();
19140        self.temporary_diff_override = true;
19141    }
19142
19143    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19144        self.temporary_diff_override = false;
19145        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19146        self.buffer.update(cx, |buffer, cx| {
19147            buffer.set_all_diff_hunks_collapsed(cx);
19148        });
19149
19150        if let Some(project) = self.project.clone() {
19151            self.load_diff_task = Some(
19152                update_uncommitted_diff_for_buffer(
19153                    cx.entity(),
19154                    &project,
19155                    self.buffer.read(cx).all_buffers(),
19156                    self.buffer.clone(),
19157                    cx,
19158                )
19159                .shared(),
19160            );
19161        }
19162    }
19163
19164    fn on_display_map_changed(
19165        &mut self,
19166        _: Entity<DisplayMap>,
19167        _: &mut Window,
19168        cx: &mut Context<Self>,
19169    ) {
19170        cx.notify();
19171    }
19172
19173    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19174        let new_severity = if self.diagnostics_enabled() {
19175            EditorSettings::get_global(cx)
19176                .diagnostics_max_severity
19177                .unwrap_or(DiagnosticSeverity::Hint)
19178        } else {
19179            DiagnosticSeverity::Off
19180        };
19181        self.set_max_diagnostics_severity(new_severity, cx);
19182        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19183        self.update_edit_prediction_settings(cx);
19184        self.refresh_inline_completion(true, false, window, cx);
19185        self.refresh_inlay_hints(
19186            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19187                self.selections.newest_anchor().head(),
19188                &self.buffer.read(cx).snapshot(cx),
19189                cx,
19190            )),
19191            cx,
19192        );
19193
19194        let old_cursor_shape = self.cursor_shape;
19195
19196        {
19197            let editor_settings = EditorSettings::get_global(cx);
19198            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19199            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19200            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19201            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19202            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19203        }
19204
19205        if old_cursor_shape != self.cursor_shape {
19206            cx.emit(EditorEvent::CursorShapeChanged);
19207        }
19208
19209        let project_settings = ProjectSettings::get_global(cx);
19210        self.serialize_dirty_buffers =
19211            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19212
19213        if self.mode.is_full() {
19214            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19215            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19216            if self.show_inline_diagnostics != show_inline_diagnostics {
19217                self.show_inline_diagnostics = show_inline_diagnostics;
19218                self.refresh_inline_diagnostics(false, window, cx);
19219            }
19220
19221            if self.git_blame_inline_enabled != inline_blame_enabled {
19222                self.toggle_git_blame_inline_internal(false, window, cx);
19223            }
19224
19225            let minimap_settings = EditorSettings::get_global(cx).minimap;
19226            if self.minimap_visibility != MinimapVisibility::Disabled {
19227                if self.minimap_visibility.settings_visibility()
19228                    != minimap_settings.minimap_enabled()
19229                {
19230                    self.set_minimap_visibility(
19231                        MinimapVisibility::for_mode(self.mode(), cx),
19232                        window,
19233                        cx,
19234                    );
19235                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19236                    minimap_entity.update(cx, |minimap_editor, cx| {
19237                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19238                    })
19239                }
19240            }
19241        }
19242
19243        cx.notify();
19244    }
19245
19246    pub fn set_searchable(&mut self, searchable: bool) {
19247        self.searchable = searchable;
19248    }
19249
19250    pub fn searchable(&self) -> bool {
19251        self.searchable
19252    }
19253
19254    fn open_proposed_changes_editor(
19255        &mut self,
19256        _: &OpenProposedChangesEditor,
19257        window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) {
19260        let Some(workspace) = self.workspace() else {
19261            cx.propagate();
19262            return;
19263        };
19264
19265        let selections = self.selections.all::<usize>(cx);
19266        let multi_buffer = self.buffer.read(cx);
19267        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19268        let mut new_selections_by_buffer = HashMap::default();
19269        for selection in selections {
19270            for (buffer, range, _) in
19271                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19272            {
19273                let mut range = range.to_point(buffer);
19274                range.start.column = 0;
19275                range.end.column = buffer.line_len(range.end.row);
19276                new_selections_by_buffer
19277                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19278                    .or_insert(Vec::new())
19279                    .push(range)
19280            }
19281        }
19282
19283        let proposed_changes_buffers = new_selections_by_buffer
19284            .into_iter()
19285            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19286            .collect::<Vec<_>>();
19287        let proposed_changes_editor = cx.new(|cx| {
19288            ProposedChangesEditor::new(
19289                "Proposed changes",
19290                proposed_changes_buffers,
19291                self.project.clone(),
19292                window,
19293                cx,
19294            )
19295        });
19296
19297        window.defer(cx, move |window, cx| {
19298            workspace.update(cx, |workspace, cx| {
19299                workspace.active_pane().update(cx, |pane, cx| {
19300                    pane.add_item(
19301                        Box::new(proposed_changes_editor),
19302                        true,
19303                        true,
19304                        None,
19305                        window,
19306                        cx,
19307                    );
19308                });
19309            });
19310        });
19311    }
19312
19313    pub fn open_excerpts_in_split(
19314        &mut self,
19315        _: &OpenExcerptsSplit,
19316        window: &mut Window,
19317        cx: &mut Context<Self>,
19318    ) {
19319        self.open_excerpts_common(None, true, window, cx)
19320    }
19321
19322    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19323        self.open_excerpts_common(None, false, window, cx)
19324    }
19325
19326    fn open_excerpts_common(
19327        &mut self,
19328        jump_data: Option<JumpData>,
19329        split: bool,
19330        window: &mut Window,
19331        cx: &mut Context<Self>,
19332    ) {
19333        let Some(workspace) = self.workspace() else {
19334            cx.propagate();
19335            return;
19336        };
19337
19338        if self.buffer.read(cx).is_singleton() {
19339            cx.propagate();
19340            return;
19341        }
19342
19343        let mut new_selections_by_buffer = HashMap::default();
19344        match &jump_data {
19345            Some(JumpData::MultiBufferPoint {
19346                excerpt_id,
19347                position,
19348                anchor,
19349                line_offset_from_top,
19350            }) => {
19351                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19352                if let Some(buffer) = multi_buffer_snapshot
19353                    .buffer_id_for_excerpt(*excerpt_id)
19354                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19355                {
19356                    let buffer_snapshot = buffer.read(cx).snapshot();
19357                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19358                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19359                    } else {
19360                        buffer_snapshot.clip_point(*position, Bias::Left)
19361                    };
19362                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19363                    new_selections_by_buffer.insert(
19364                        buffer,
19365                        (
19366                            vec![jump_to_offset..jump_to_offset],
19367                            Some(*line_offset_from_top),
19368                        ),
19369                    );
19370                }
19371            }
19372            Some(JumpData::MultiBufferRow {
19373                row,
19374                line_offset_from_top,
19375            }) => {
19376                let point = MultiBufferPoint::new(row.0, 0);
19377                if let Some((buffer, buffer_point, _)) =
19378                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19379                {
19380                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19381                    new_selections_by_buffer
19382                        .entry(buffer)
19383                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19384                        .0
19385                        .push(buffer_offset..buffer_offset)
19386                }
19387            }
19388            None => {
19389                let selections = self.selections.all::<usize>(cx);
19390                let multi_buffer = self.buffer.read(cx);
19391                for selection in selections {
19392                    for (snapshot, range, _, anchor) in multi_buffer
19393                        .snapshot(cx)
19394                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19395                    {
19396                        if let Some(anchor) = anchor {
19397                            // selection is in a deleted hunk
19398                            let Some(buffer_id) = anchor.buffer_id else {
19399                                continue;
19400                            };
19401                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19402                                continue;
19403                            };
19404                            let offset = text::ToOffset::to_offset(
19405                                &anchor.text_anchor,
19406                                &buffer_handle.read(cx).snapshot(),
19407                            );
19408                            let range = offset..offset;
19409                            new_selections_by_buffer
19410                                .entry(buffer_handle)
19411                                .or_insert((Vec::new(), None))
19412                                .0
19413                                .push(range)
19414                        } else {
19415                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19416                            else {
19417                                continue;
19418                            };
19419                            new_selections_by_buffer
19420                                .entry(buffer_handle)
19421                                .or_insert((Vec::new(), None))
19422                                .0
19423                                .push(range)
19424                        }
19425                    }
19426                }
19427            }
19428        }
19429
19430        new_selections_by_buffer
19431            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19432
19433        if new_selections_by_buffer.is_empty() {
19434            return;
19435        }
19436
19437        // We defer the pane interaction because we ourselves are a workspace item
19438        // and activating a new item causes the pane to call a method on us reentrantly,
19439        // which panics if we're on the stack.
19440        window.defer(cx, move |window, cx| {
19441            workspace.update(cx, |workspace, cx| {
19442                let pane = if split {
19443                    workspace.adjacent_pane(window, cx)
19444                } else {
19445                    workspace.active_pane().clone()
19446                };
19447
19448                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19449                    let editor = buffer
19450                        .read(cx)
19451                        .file()
19452                        .is_none()
19453                        .then(|| {
19454                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19455                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19456                            // Instead, we try to activate the existing editor in the pane first.
19457                            let (editor, pane_item_index) =
19458                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19459                                    let editor = item.downcast::<Editor>()?;
19460                                    let singleton_buffer =
19461                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19462                                    if singleton_buffer == buffer {
19463                                        Some((editor, i))
19464                                    } else {
19465                                        None
19466                                    }
19467                                })?;
19468                            pane.update(cx, |pane, cx| {
19469                                pane.activate_item(pane_item_index, true, true, window, cx)
19470                            });
19471                            Some(editor)
19472                        })
19473                        .flatten()
19474                        .unwrap_or_else(|| {
19475                            workspace.open_project_item::<Self>(
19476                                pane.clone(),
19477                                buffer,
19478                                true,
19479                                true,
19480                                window,
19481                                cx,
19482                            )
19483                        });
19484
19485                    editor.update(cx, |editor, cx| {
19486                        let autoscroll = match scroll_offset {
19487                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19488                            None => Autoscroll::newest(),
19489                        };
19490                        let nav_history = editor.nav_history.take();
19491                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19492                            s.select_ranges(ranges);
19493                        });
19494                        editor.nav_history = nav_history;
19495                    });
19496                }
19497            })
19498        });
19499    }
19500
19501    // For now, don't allow opening excerpts in buffers that aren't backed by
19502    // regular project files.
19503    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19504        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19505    }
19506
19507    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19508        let snapshot = self.buffer.read(cx).read(cx);
19509        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19510        Some(
19511            ranges
19512                .iter()
19513                .map(move |range| {
19514                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19515                })
19516                .collect(),
19517        )
19518    }
19519
19520    fn selection_replacement_ranges(
19521        &self,
19522        range: Range<OffsetUtf16>,
19523        cx: &mut App,
19524    ) -> Vec<Range<OffsetUtf16>> {
19525        let selections = self.selections.all::<OffsetUtf16>(cx);
19526        let newest_selection = selections
19527            .iter()
19528            .max_by_key(|selection| selection.id)
19529            .unwrap();
19530        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19531        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19532        let snapshot = self.buffer.read(cx).read(cx);
19533        selections
19534            .into_iter()
19535            .map(|mut selection| {
19536                selection.start.0 =
19537                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19538                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19539                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19540                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19541            })
19542            .collect()
19543    }
19544
19545    fn report_editor_event(
19546        &self,
19547        event_type: &'static str,
19548        file_extension: Option<String>,
19549        cx: &App,
19550    ) {
19551        if cfg!(any(test, feature = "test-support")) {
19552            return;
19553        }
19554
19555        let Some(project) = &self.project else { return };
19556
19557        // If None, we are in a file without an extension
19558        let file = self
19559            .buffer
19560            .read(cx)
19561            .as_singleton()
19562            .and_then(|b| b.read(cx).file());
19563        let file_extension = file_extension.or(file
19564            .as_ref()
19565            .and_then(|file| Path::new(file.file_name(cx)).extension())
19566            .and_then(|e| e.to_str())
19567            .map(|a| a.to_string()));
19568
19569        let vim_mode = vim_enabled(cx);
19570
19571        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19572        let copilot_enabled = edit_predictions_provider
19573            == language::language_settings::EditPredictionProvider::Copilot;
19574        let copilot_enabled_for_language = self
19575            .buffer
19576            .read(cx)
19577            .language_settings(cx)
19578            .show_edit_predictions;
19579
19580        let project = project.read(cx);
19581        telemetry::event!(
19582            event_type,
19583            file_extension,
19584            vim_mode,
19585            copilot_enabled,
19586            copilot_enabled_for_language,
19587            edit_predictions_provider,
19588            is_via_ssh = project.is_via_ssh(),
19589        );
19590    }
19591
19592    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19593    /// with each line being an array of {text, highlight} objects.
19594    fn copy_highlight_json(
19595        &mut self,
19596        _: &CopyHighlightJson,
19597        window: &mut Window,
19598        cx: &mut Context<Self>,
19599    ) {
19600        #[derive(Serialize)]
19601        struct Chunk<'a> {
19602            text: String,
19603            highlight: Option<&'a str>,
19604        }
19605
19606        let snapshot = self.buffer.read(cx).snapshot(cx);
19607        let range = self
19608            .selected_text_range(false, window, cx)
19609            .and_then(|selection| {
19610                if selection.range.is_empty() {
19611                    None
19612                } else {
19613                    Some(selection.range)
19614                }
19615            })
19616            .unwrap_or_else(|| 0..snapshot.len());
19617
19618        let chunks = snapshot.chunks(range, true);
19619        let mut lines = Vec::new();
19620        let mut line: VecDeque<Chunk> = VecDeque::new();
19621
19622        let Some(style) = self.style.as_ref() else {
19623            return;
19624        };
19625
19626        for chunk in chunks {
19627            let highlight = chunk
19628                .syntax_highlight_id
19629                .and_then(|id| id.name(&style.syntax));
19630            let mut chunk_lines = chunk.text.split('\n').peekable();
19631            while let Some(text) = chunk_lines.next() {
19632                let mut merged_with_last_token = false;
19633                if let Some(last_token) = line.back_mut() {
19634                    if last_token.highlight == highlight {
19635                        last_token.text.push_str(text);
19636                        merged_with_last_token = true;
19637                    }
19638                }
19639
19640                if !merged_with_last_token {
19641                    line.push_back(Chunk {
19642                        text: text.into(),
19643                        highlight,
19644                    });
19645                }
19646
19647                if chunk_lines.peek().is_some() {
19648                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19649                        line.pop_front();
19650                    }
19651                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19652                        line.pop_back();
19653                    }
19654
19655                    lines.push(mem::take(&mut line));
19656                }
19657            }
19658        }
19659
19660        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19661            return;
19662        };
19663        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19664    }
19665
19666    pub fn open_context_menu(
19667        &mut self,
19668        _: &OpenContextMenu,
19669        window: &mut Window,
19670        cx: &mut Context<Self>,
19671    ) {
19672        self.request_autoscroll(Autoscroll::newest(), cx);
19673        let position = self.selections.newest_display(cx).start;
19674        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19675    }
19676
19677    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19678        &self.inlay_hint_cache
19679    }
19680
19681    pub fn replay_insert_event(
19682        &mut self,
19683        text: &str,
19684        relative_utf16_range: Option<Range<isize>>,
19685        window: &mut Window,
19686        cx: &mut Context<Self>,
19687    ) {
19688        if !self.input_enabled {
19689            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19690            return;
19691        }
19692        if let Some(relative_utf16_range) = relative_utf16_range {
19693            let selections = self.selections.all::<OffsetUtf16>(cx);
19694            self.change_selections(None, window, cx, |s| {
19695                let new_ranges = selections.into_iter().map(|range| {
19696                    let start = OffsetUtf16(
19697                        range
19698                            .head()
19699                            .0
19700                            .saturating_add_signed(relative_utf16_range.start),
19701                    );
19702                    let end = OffsetUtf16(
19703                        range
19704                            .head()
19705                            .0
19706                            .saturating_add_signed(relative_utf16_range.end),
19707                    );
19708                    start..end
19709                });
19710                s.select_ranges(new_ranges);
19711            });
19712        }
19713
19714        self.handle_input(text, window, cx);
19715    }
19716
19717    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19718        let Some(provider) = self.semantics_provider.as_ref() else {
19719            return false;
19720        };
19721
19722        let mut supports = false;
19723        self.buffer().update(cx, |this, cx| {
19724            this.for_each_buffer(|buffer| {
19725                supports |= provider.supports_inlay_hints(buffer, cx);
19726            });
19727        });
19728
19729        supports
19730    }
19731
19732    pub fn is_focused(&self, window: &Window) -> bool {
19733        self.focus_handle.is_focused(window)
19734    }
19735
19736    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19737        cx.emit(EditorEvent::Focused);
19738
19739        if let Some(descendant) = self
19740            .last_focused_descendant
19741            .take()
19742            .and_then(|descendant| descendant.upgrade())
19743        {
19744            window.focus(&descendant);
19745        } else {
19746            if let Some(blame) = self.blame.as_ref() {
19747                blame.update(cx, GitBlame::focus)
19748            }
19749
19750            self.blink_manager.update(cx, BlinkManager::enable);
19751            self.show_cursor_names(window, cx);
19752            self.buffer.update(cx, |buffer, cx| {
19753                buffer.finalize_last_transaction(cx);
19754                if self.leader_id.is_none() {
19755                    buffer.set_active_selections(
19756                        &self.selections.disjoint_anchors(),
19757                        self.selections.line_mode,
19758                        self.cursor_shape,
19759                        cx,
19760                    );
19761                }
19762            });
19763        }
19764    }
19765
19766    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19767        cx.emit(EditorEvent::FocusedIn)
19768    }
19769
19770    fn handle_focus_out(
19771        &mut self,
19772        event: FocusOutEvent,
19773        _window: &mut Window,
19774        cx: &mut Context<Self>,
19775    ) {
19776        if event.blurred != self.focus_handle {
19777            self.last_focused_descendant = Some(event.blurred);
19778        }
19779        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19780    }
19781
19782    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19783        self.blink_manager.update(cx, BlinkManager::disable);
19784        self.buffer
19785            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19786
19787        if let Some(blame) = self.blame.as_ref() {
19788            blame.update(cx, GitBlame::blur)
19789        }
19790        if !self.hover_state.focused(window, cx) {
19791            hide_hover(self, cx);
19792        }
19793        if !self
19794            .context_menu
19795            .borrow()
19796            .as_ref()
19797            .is_some_and(|context_menu| context_menu.focused(window, cx))
19798        {
19799            self.hide_context_menu(window, cx);
19800        }
19801        self.discard_inline_completion(false, cx);
19802        cx.emit(EditorEvent::Blurred);
19803        cx.notify();
19804    }
19805
19806    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19807        let mut pending: String = window
19808            .pending_input_keystrokes()
19809            .into_iter()
19810            .flatten()
19811            .filter_map(|keystroke| {
19812                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19813                    keystroke.key_char.clone()
19814                } else {
19815                    None
19816                }
19817            })
19818            .collect();
19819
19820        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19821            pending = "".to_string();
19822        }
19823
19824        let existing_pending = self
19825            .text_highlights::<PendingInput>(cx)
19826            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19827        if existing_pending.is_none() && pending.is_empty() {
19828            return;
19829        }
19830        let transaction =
19831            self.transact(window, cx, |this, window, cx| {
19832                let selections = this.selections.all::<usize>(cx);
19833                let edits = selections
19834                    .iter()
19835                    .map(|selection| (selection.end..selection.end, pending.clone()));
19836                this.edit(edits, cx);
19837                this.change_selections(None, window, cx, |s| {
19838                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19839                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19840                    }));
19841                });
19842                if let Some(existing_ranges) = existing_pending {
19843                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19844                    this.edit(edits, cx);
19845                }
19846            });
19847
19848        let snapshot = self.snapshot(window, cx);
19849        let ranges = self
19850            .selections
19851            .all::<usize>(cx)
19852            .into_iter()
19853            .map(|selection| {
19854                snapshot.buffer_snapshot.anchor_after(selection.end)
19855                    ..snapshot
19856                        .buffer_snapshot
19857                        .anchor_before(selection.end + pending.len())
19858            })
19859            .collect();
19860
19861        if pending.is_empty() {
19862            self.clear_highlights::<PendingInput>(cx);
19863        } else {
19864            self.highlight_text::<PendingInput>(
19865                ranges,
19866                HighlightStyle {
19867                    underline: Some(UnderlineStyle {
19868                        thickness: px(1.),
19869                        color: None,
19870                        wavy: false,
19871                    }),
19872                    ..Default::default()
19873                },
19874                cx,
19875            );
19876        }
19877
19878        self.ime_transaction = self.ime_transaction.or(transaction);
19879        if let Some(transaction) = self.ime_transaction {
19880            self.buffer.update(cx, |buffer, cx| {
19881                buffer.group_until_transaction(transaction, cx);
19882            });
19883        }
19884
19885        if self.text_highlights::<PendingInput>(cx).is_none() {
19886            self.ime_transaction.take();
19887        }
19888    }
19889
19890    pub fn register_action_renderer(
19891        &mut self,
19892        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19893    ) -> Subscription {
19894        let id = self.next_editor_action_id.post_inc();
19895        self.editor_actions
19896            .borrow_mut()
19897            .insert(id, Box::new(listener));
19898
19899        let editor_actions = self.editor_actions.clone();
19900        Subscription::new(move || {
19901            editor_actions.borrow_mut().remove(&id);
19902        })
19903    }
19904
19905    pub fn register_action<A: Action>(
19906        &mut self,
19907        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19908    ) -> Subscription {
19909        let id = self.next_editor_action_id.post_inc();
19910        let listener = Arc::new(listener);
19911        self.editor_actions.borrow_mut().insert(
19912            id,
19913            Box::new(move |_, window, _| {
19914                let listener = listener.clone();
19915                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19916                    let action = action.downcast_ref().unwrap();
19917                    if phase == DispatchPhase::Bubble {
19918                        listener(action, window, cx)
19919                    }
19920                })
19921            }),
19922        );
19923
19924        let editor_actions = self.editor_actions.clone();
19925        Subscription::new(move || {
19926            editor_actions.borrow_mut().remove(&id);
19927        })
19928    }
19929
19930    pub fn file_header_size(&self) -> u32 {
19931        FILE_HEADER_HEIGHT
19932    }
19933
19934    pub fn restore(
19935        &mut self,
19936        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19937        window: &mut Window,
19938        cx: &mut Context<Self>,
19939    ) {
19940        let workspace = self.workspace();
19941        let project = self.project.as_ref();
19942        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19943            let mut tasks = Vec::new();
19944            for (buffer_id, changes) in revert_changes {
19945                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19946                    buffer.update(cx, |buffer, cx| {
19947                        buffer.edit(
19948                            changes
19949                                .into_iter()
19950                                .map(|(range, text)| (range, text.to_string())),
19951                            None,
19952                            cx,
19953                        );
19954                    });
19955
19956                    if let Some(project) =
19957                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19958                    {
19959                        project.update(cx, |project, cx| {
19960                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19961                        })
19962                    }
19963                }
19964            }
19965            tasks
19966        });
19967        cx.spawn_in(window, async move |_, cx| {
19968            for (buffer, task) in save_tasks {
19969                let result = task.await;
19970                if result.is_err() {
19971                    let Some(path) = buffer
19972                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19973                        .ok()
19974                    else {
19975                        continue;
19976                    };
19977                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19978                        let Some(task) = cx
19979                            .update_window_entity(&workspace, |workspace, window, cx| {
19980                                workspace
19981                                    .open_path_preview(path, None, false, false, false, window, cx)
19982                            })
19983                            .ok()
19984                        else {
19985                            continue;
19986                        };
19987                        task.await.log_err();
19988                    }
19989                }
19990            }
19991        })
19992        .detach();
19993        self.change_selections(None, window, cx, |selections| selections.refresh());
19994    }
19995
19996    pub fn to_pixel_point(
19997        &self,
19998        source: multi_buffer::Anchor,
19999        editor_snapshot: &EditorSnapshot,
20000        window: &mut Window,
20001    ) -> Option<gpui::Point<Pixels>> {
20002        let source_point = source.to_display_point(editor_snapshot);
20003        self.display_to_pixel_point(source_point, editor_snapshot, window)
20004    }
20005
20006    pub fn display_to_pixel_point(
20007        &self,
20008        source: DisplayPoint,
20009        editor_snapshot: &EditorSnapshot,
20010        window: &mut Window,
20011    ) -> Option<gpui::Point<Pixels>> {
20012        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20013        let text_layout_details = self.text_layout_details(window);
20014        let scroll_top = text_layout_details
20015            .scroll_anchor
20016            .scroll_position(editor_snapshot)
20017            .y;
20018
20019        if source.row().as_f32() < scroll_top.floor() {
20020            return None;
20021        }
20022        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20023        let source_y = line_height * (source.row().as_f32() - scroll_top);
20024        Some(gpui::Point::new(source_x, source_y))
20025    }
20026
20027    pub fn has_visible_completions_menu(&self) -> bool {
20028        !self.edit_prediction_preview_is_active()
20029            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20030                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20031            })
20032    }
20033
20034    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20035        if self.mode.is_minimap() {
20036            return;
20037        }
20038        self.addons
20039            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20040    }
20041
20042    pub fn unregister_addon<T: Addon>(&mut self) {
20043        self.addons.remove(&std::any::TypeId::of::<T>());
20044    }
20045
20046    pub fn addon<T: Addon>(&self) -> Option<&T> {
20047        let type_id = std::any::TypeId::of::<T>();
20048        self.addons
20049            .get(&type_id)
20050            .and_then(|item| item.to_any().downcast_ref::<T>())
20051    }
20052
20053    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20054        let type_id = std::any::TypeId::of::<T>();
20055        self.addons
20056            .get_mut(&type_id)
20057            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20058    }
20059
20060    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20061        let text_layout_details = self.text_layout_details(window);
20062        let style = &text_layout_details.editor_style;
20063        let font_id = window.text_system().resolve_font(&style.text.font());
20064        let font_size = style.text.font_size.to_pixels(window.rem_size());
20065        let line_height = style.text.line_height_in_pixels(window.rem_size());
20066        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20067
20068        gpui::Size::new(em_width, line_height)
20069    }
20070
20071    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20072        self.load_diff_task.clone()
20073    }
20074
20075    fn read_metadata_from_db(
20076        &mut self,
20077        item_id: u64,
20078        workspace_id: WorkspaceId,
20079        window: &mut Window,
20080        cx: &mut Context<Editor>,
20081    ) {
20082        if self.is_singleton(cx)
20083            && !self.mode.is_minimap()
20084            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20085        {
20086            let buffer_snapshot = OnceCell::new();
20087
20088            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20089                if !folds.is_empty() {
20090                    let snapshot =
20091                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20092                    self.fold_ranges(
20093                        folds
20094                            .into_iter()
20095                            .map(|(start, end)| {
20096                                snapshot.clip_offset(start, Bias::Left)
20097                                    ..snapshot.clip_offset(end, Bias::Right)
20098                            })
20099                            .collect(),
20100                        false,
20101                        window,
20102                        cx,
20103                    );
20104                }
20105            }
20106
20107            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20108                if !selections.is_empty() {
20109                    let snapshot =
20110                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20111                    // skip adding the initial selection to selection history
20112                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20113                    self.change_selections(None, window, cx, |s| {
20114                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20115                            snapshot.clip_offset(start, Bias::Left)
20116                                ..snapshot.clip_offset(end, Bias::Right)
20117                        }));
20118                    });
20119                    self.selection_history.mode = SelectionHistoryMode::Normal;
20120                }
20121            };
20122        }
20123
20124        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20125    }
20126}
20127
20128fn vim_enabled(cx: &App) -> bool {
20129    cx.global::<SettingsStore>()
20130        .raw_user_settings()
20131        .get("vim_mode")
20132        == Some(&serde_json::Value::Bool(true))
20133}
20134
20135fn process_completion_for_edit(
20136    completion: &Completion,
20137    intent: CompletionIntent,
20138    buffer: &Entity<Buffer>,
20139    cursor_position: &text::Anchor,
20140    cx: &mut Context<Editor>,
20141) -> CompletionEdit {
20142    let buffer = buffer.read(cx);
20143    let buffer_snapshot = buffer.snapshot();
20144    let (snippet, new_text) = if completion.is_snippet() {
20145        // Workaround for typescript language server issues so that methods don't expand within
20146        // strings and functions with type expressions. The previous point is used because the query
20147        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20148        let mut snippet_source = completion.new_text.clone();
20149        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20150        previous_point.column = previous_point.column.saturating_sub(1);
20151        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20152            if scope.prefers_label_for_snippet_in_completion() {
20153                if let Some(label) = completion.label() {
20154                    if matches!(
20155                        completion.kind(),
20156                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20157                    ) {
20158                        snippet_source = label;
20159                    }
20160                }
20161            }
20162        }
20163        match Snippet::parse(&snippet_source).log_err() {
20164            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20165            None => (None, completion.new_text.clone()),
20166        }
20167    } else {
20168        (None, completion.new_text.clone())
20169    };
20170
20171    let mut range_to_replace = {
20172        let replace_range = &completion.replace_range;
20173        if let CompletionSource::Lsp {
20174            insert_range: Some(insert_range),
20175            ..
20176        } = &completion.source
20177        {
20178            debug_assert_eq!(
20179                insert_range.start, replace_range.start,
20180                "insert_range and replace_range should start at the same position"
20181            );
20182            debug_assert!(
20183                insert_range
20184                    .start
20185                    .cmp(&cursor_position, &buffer_snapshot)
20186                    .is_le(),
20187                "insert_range should start before or at cursor position"
20188            );
20189            debug_assert!(
20190                replace_range
20191                    .start
20192                    .cmp(&cursor_position, &buffer_snapshot)
20193                    .is_le(),
20194                "replace_range should start before or at cursor position"
20195            );
20196            debug_assert!(
20197                insert_range
20198                    .end
20199                    .cmp(&cursor_position, &buffer_snapshot)
20200                    .is_le(),
20201                "insert_range should end before or at cursor position"
20202            );
20203
20204            let should_replace = match intent {
20205                CompletionIntent::CompleteWithInsert => false,
20206                CompletionIntent::CompleteWithReplace => true,
20207                CompletionIntent::Complete | CompletionIntent::Compose => {
20208                    let insert_mode =
20209                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20210                            .completions
20211                            .lsp_insert_mode;
20212                    match insert_mode {
20213                        LspInsertMode::Insert => false,
20214                        LspInsertMode::Replace => true,
20215                        LspInsertMode::ReplaceSubsequence => {
20216                            let mut text_to_replace = buffer.chars_for_range(
20217                                buffer.anchor_before(replace_range.start)
20218                                    ..buffer.anchor_after(replace_range.end),
20219                            );
20220                            let mut current_needle = text_to_replace.next();
20221                            for haystack_ch in completion.label.text.chars() {
20222                                if let Some(needle_ch) = current_needle {
20223                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20224                                        current_needle = text_to_replace.next();
20225                                    }
20226                                }
20227                            }
20228                            current_needle.is_none()
20229                        }
20230                        LspInsertMode::ReplaceSuffix => {
20231                            if replace_range
20232                                .end
20233                                .cmp(&cursor_position, &buffer_snapshot)
20234                                .is_gt()
20235                            {
20236                                let range_after_cursor = *cursor_position..replace_range.end;
20237                                let text_after_cursor = buffer
20238                                    .text_for_range(
20239                                        buffer.anchor_before(range_after_cursor.start)
20240                                            ..buffer.anchor_after(range_after_cursor.end),
20241                                    )
20242                                    .collect::<String>()
20243                                    .to_ascii_lowercase();
20244                                completion
20245                                    .label
20246                                    .text
20247                                    .to_ascii_lowercase()
20248                                    .ends_with(&text_after_cursor)
20249                            } else {
20250                                true
20251                            }
20252                        }
20253                    }
20254                }
20255            };
20256
20257            if should_replace {
20258                replace_range.clone()
20259            } else {
20260                insert_range.clone()
20261            }
20262        } else {
20263            replace_range.clone()
20264        }
20265    };
20266
20267    if range_to_replace
20268        .end
20269        .cmp(&cursor_position, &buffer_snapshot)
20270        .is_lt()
20271    {
20272        range_to_replace.end = *cursor_position;
20273    }
20274
20275    CompletionEdit {
20276        new_text,
20277        replace_range: range_to_replace.to_offset(&buffer),
20278        snippet,
20279    }
20280}
20281
20282struct CompletionEdit {
20283    new_text: String,
20284    replace_range: Range<usize>,
20285    snippet: Option<Snippet>,
20286}
20287
20288fn insert_extra_newline_brackets(
20289    buffer: &MultiBufferSnapshot,
20290    range: Range<usize>,
20291    language: &language::LanguageScope,
20292) -> bool {
20293    let leading_whitespace_len = buffer
20294        .reversed_chars_at(range.start)
20295        .take_while(|c| c.is_whitespace() && *c != '\n')
20296        .map(|c| c.len_utf8())
20297        .sum::<usize>();
20298    let trailing_whitespace_len = buffer
20299        .chars_at(range.end)
20300        .take_while(|c| c.is_whitespace() && *c != '\n')
20301        .map(|c| c.len_utf8())
20302        .sum::<usize>();
20303    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20304
20305    language.brackets().any(|(pair, enabled)| {
20306        let pair_start = pair.start.trim_end();
20307        let pair_end = pair.end.trim_start();
20308
20309        enabled
20310            && pair.newline
20311            && buffer.contains_str_at(range.end, pair_end)
20312            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20313    })
20314}
20315
20316fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20317    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20318        [(buffer, range, _)] => (*buffer, range.clone()),
20319        _ => return false,
20320    };
20321    let pair = {
20322        let mut result: Option<BracketMatch> = None;
20323
20324        for pair in buffer
20325            .all_bracket_ranges(range.clone())
20326            .filter(move |pair| {
20327                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20328            })
20329        {
20330            let len = pair.close_range.end - pair.open_range.start;
20331
20332            if let Some(existing) = &result {
20333                let existing_len = existing.close_range.end - existing.open_range.start;
20334                if len > existing_len {
20335                    continue;
20336                }
20337            }
20338
20339            result = Some(pair);
20340        }
20341
20342        result
20343    };
20344    let Some(pair) = pair else {
20345        return false;
20346    };
20347    pair.newline_only
20348        && buffer
20349            .chars_for_range(pair.open_range.end..range.start)
20350            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20351            .all(|c| c.is_whitespace() && c != '\n')
20352}
20353
20354fn update_uncommitted_diff_for_buffer(
20355    editor: Entity<Editor>,
20356    project: &Entity<Project>,
20357    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20358    buffer: Entity<MultiBuffer>,
20359    cx: &mut App,
20360) -> Task<()> {
20361    let mut tasks = Vec::new();
20362    project.update(cx, |project, cx| {
20363        for buffer in buffers {
20364            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20365                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20366            }
20367        }
20368    });
20369    cx.spawn(async move |cx| {
20370        let diffs = future::join_all(tasks).await;
20371        if editor
20372            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20373            .unwrap_or(false)
20374        {
20375            return;
20376        }
20377
20378        buffer
20379            .update(cx, |buffer, cx| {
20380                for diff in diffs.into_iter().flatten() {
20381                    buffer.add_diff(diff, cx);
20382                }
20383            })
20384            .ok();
20385    })
20386}
20387
20388fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20389    let tab_size = tab_size.get() as usize;
20390    let mut width = offset;
20391
20392    for ch in text.chars() {
20393        width += if ch == '\t' {
20394            tab_size - (width % tab_size)
20395        } else {
20396            1
20397        };
20398    }
20399
20400    width - offset
20401}
20402
20403#[cfg(test)]
20404mod tests {
20405    use super::*;
20406
20407    #[test]
20408    fn test_string_size_with_expanded_tabs() {
20409        let nz = |val| NonZeroU32::new(val).unwrap();
20410        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20411        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20412        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20413        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20414        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20415        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20416        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20417        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20418    }
20419}
20420
20421/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20422struct WordBreakingTokenizer<'a> {
20423    input: &'a str,
20424}
20425
20426impl<'a> WordBreakingTokenizer<'a> {
20427    fn new(input: &'a str) -> Self {
20428        Self { input }
20429    }
20430}
20431
20432fn is_char_ideographic(ch: char) -> bool {
20433    use unicode_script::Script::*;
20434    use unicode_script::UnicodeScript;
20435    matches!(ch.script(), Han | Tangut | Yi)
20436}
20437
20438fn is_grapheme_ideographic(text: &str) -> bool {
20439    text.chars().any(is_char_ideographic)
20440}
20441
20442fn is_grapheme_whitespace(text: &str) -> bool {
20443    text.chars().any(|x| x.is_whitespace())
20444}
20445
20446fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20447    text.chars().next().map_or(false, |ch| {
20448        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20449    })
20450}
20451
20452#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20453enum WordBreakToken<'a> {
20454    Word { token: &'a str, grapheme_len: usize },
20455    InlineWhitespace { token: &'a str, grapheme_len: usize },
20456    Newline,
20457}
20458
20459impl<'a> Iterator for WordBreakingTokenizer<'a> {
20460    /// Yields a span, the count of graphemes in the token, and whether it was
20461    /// whitespace. Note that it also breaks at word boundaries.
20462    type Item = WordBreakToken<'a>;
20463
20464    fn next(&mut self) -> Option<Self::Item> {
20465        use unicode_segmentation::UnicodeSegmentation;
20466        if self.input.is_empty() {
20467            return None;
20468        }
20469
20470        let mut iter = self.input.graphemes(true).peekable();
20471        let mut offset = 0;
20472        let mut grapheme_len = 0;
20473        if let Some(first_grapheme) = iter.next() {
20474            let is_newline = first_grapheme == "\n";
20475            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20476            offset += first_grapheme.len();
20477            grapheme_len += 1;
20478            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20479                if let Some(grapheme) = iter.peek().copied() {
20480                    if should_stay_with_preceding_ideograph(grapheme) {
20481                        offset += grapheme.len();
20482                        grapheme_len += 1;
20483                    }
20484                }
20485            } else {
20486                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20487                let mut next_word_bound = words.peek().copied();
20488                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20489                    next_word_bound = words.next();
20490                }
20491                while let Some(grapheme) = iter.peek().copied() {
20492                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20493                        break;
20494                    };
20495                    if is_grapheme_whitespace(grapheme) != is_whitespace
20496                        || (grapheme == "\n") != is_newline
20497                    {
20498                        break;
20499                    };
20500                    offset += grapheme.len();
20501                    grapheme_len += 1;
20502                    iter.next();
20503                }
20504            }
20505            let token = &self.input[..offset];
20506            self.input = &self.input[offset..];
20507            if token == "\n" {
20508                Some(WordBreakToken::Newline)
20509            } else if is_whitespace {
20510                Some(WordBreakToken::InlineWhitespace {
20511                    token,
20512                    grapheme_len,
20513                })
20514            } else {
20515                Some(WordBreakToken::Word {
20516                    token,
20517                    grapheme_len,
20518                })
20519            }
20520        } else {
20521            None
20522        }
20523    }
20524}
20525
20526#[test]
20527fn test_word_breaking_tokenizer() {
20528    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20529        ("", &[]),
20530        ("  ", &[whitespace("  ", 2)]),
20531        ("Ʒ", &[word("Ʒ", 1)]),
20532        ("Ǽ", &[word("Ǽ", 1)]),
20533        ("", &[word("", 1)]),
20534        ("⋑⋑", &[word("⋑⋑", 2)]),
20535        (
20536            "原理,进而",
20537            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20538        ),
20539        (
20540            "hello world",
20541            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20542        ),
20543        (
20544            "hello, world",
20545            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20546        ),
20547        (
20548            "  hello world",
20549            &[
20550                whitespace("  ", 2),
20551                word("hello", 5),
20552                whitespace(" ", 1),
20553                word("world", 5),
20554            ],
20555        ),
20556        (
20557            "这是什么 \n 钢笔",
20558            &[
20559                word("", 1),
20560                word("", 1),
20561                word("", 1),
20562                word("", 1),
20563                whitespace(" ", 1),
20564                newline(),
20565                whitespace(" ", 1),
20566                word("", 1),
20567                word("", 1),
20568            ],
20569        ),
20570        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20571    ];
20572
20573    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20574        WordBreakToken::Word {
20575            token,
20576            grapheme_len,
20577        }
20578    }
20579
20580    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20581        WordBreakToken::InlineWhitespace {
20582            token,
20583            grapheme_len,
20584        }
20585    }
20586
20587    fn newline() -> WordBreakToken<'static> {
20588        WordBreakToken::Newline
20589    }
20590
20591    for (input, result) in tests {
20592        assert_eq!(
20593            WordBreakingTokenizer::new(input)
20594                .collect::<Vec<_>>()
20595                .as_slice(),
20596            *result,
20597        );
20598    }
20599}
20600
20601fn wrap_with_prefix(
20602    line_prefix: String,
20603    unwrapped_text: String,
20604    wrap_column: usize,
20605    tab_size: NonZeroU32,
20606    preserve_existing_whitespace: bool,
20607) -> String {
20608    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20609    let mut wrapped_text = String::new();
20610    let mut current_line = line_prefix.clone();
20611
20612    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20613    let mut current_line_len = line_prefix_len;
20614    let mut in_whitespace = false;
20615    for token in tokenizer {
20616        let have_preceding_whitespace = in_whitespace;
20617        match token {
20618            WordBreakToken::Word {
20619                token,
20620                grapheme_len,
20621            } => {
20622                in_whitespace = false;
20623                if current_line_len + grapheme_len > wrap_column
20624                    && current_line_len != line_prefix_len
20625                {
20626                    wrapped_text.push_str(current_line.trim_end());
20627                    wrapped_text.push('\n');
20628                    current_line.truncate(line_prefix.len());
20629                    current_line_len = line_prefix_len;
20630                }
20631                current_line.push_str(token);
20632                current_line_len += grapheme_len;
20633            }
20634            WordBreakToken::InlineWhitespace {
20635                mut token,
20636                mut grapheme_len,
20637            } => {
20638                in_whitespace = true;
20639                if have_preceding_whitespace && !preserve_existing_whitespace {
20640                    continue;
20641                }
20642                if !preserve_existing_whitespace {
20643                    token = " ";
20644                    grapheme_len = 1;
20645                }
20646                if current_line_len + grapheme_len > wrap_column {
20647                    wrapped_text.push_str(current_line.trim_end());
20648                    wrapped_text.push('\n');
20649                    current_line.truncate(line_prefix.len());
20650                    current_line_len = line_prefix_len;
20651                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20652                    current_line.push_str(token);
20653                    current_line_len += grapheme_len;
20654                }
20655            }
20656            WordBreakToken::Newline => {
20657                in_whitespace = true;
20658                if preserve_existing_whitespace {
20659                    wrapped_text.push_str(current_line.trim_end());
20660                    wrapped_text.push('\n');
20661                    current_line.truncate(line_prefix.len());
20662                    current_line_len = line_prefix_len;
20663                } else if have_preceding_whitespace {
20664                    continue;
20665                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20666                {
20667                    wrapped_text.push_str(current_line.trim_end());
20668                    wrapped_text.push('\n');
20669                    current_line.truncate(line_prefix.len());
20670                    current_line_len = line_prefix_len;
20671                } else if current_line_len != line_prefix_len {
20672                    current_line.push(' ');
20673                    current_line_len += 1;
20674                }
20675            }
20676        }
20677    }
20678
20679    if !current_line.is_empty() {
20680        wrapped_text.push_str(&current_line);
20681    }
20682    wrapped_text
20683}
20684
20685#[test]
20686fn test_wrap_with_prefix() {
20687    assert_eq!(
20688        wrap_with_prefix(
20689            "# ".to_string(),
20690            "abcdefg".to_string(),
20691            4,
20692            NonZeroU32::new(4).unwrap(),
20693            false,
20694        ),
20695        "# abcdefg"
20696    );
20697    assert_eq!(
20698        wrap_with_prefix(
20699            "".to_string(),
20700            "\thello world".to_string(),
20701            8,
20702            NonZeroU32::new(4).unwrap(),
20703            false,
20704        ),
20705        "hello\nworld"
20706    );
20707    assert_eq!(
20708        wrap_with_prefix(
20709            "// ".to_string(),
20710            "xx \nyy zz aa bb cc".to_string(),
20711            12,
20712            NonZeroU32::new(4).unwrap(),
20713            false,
20714        ),
20715        "// xx yy zz\n// aa bb cc"
20716    );
20717    assert_eq!(
20718        wrap_with_prefix(
20719            String::new(),
20720            "这是什么 \n 钢笔".to_string(),
20721            3,
20722            NonZeroU32::new(4).unwrap(),
20723            false,
20724        ),
20725        "这是什\n么 钢\n"
20726    );
20727}
20728
20729pub trait CollaborationHub {
20730    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20731    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20732    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20733}
20734
20735impl CollaborationHub for Entity<Project> {
20736    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20737        self.read(cx).collaborators()
20738    }
20739
20740    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20741        self.read(cx).user_store().read(cx).participant_indices()
20742    }
20743
20744    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20745        let this = self.read(cx);
20746        let user_ids = this.collaborators().values().map(|c| c.user_id);
20747        this.user_store().read(cx).participant_names(user_ids, cx)
20748    }
20749}
20750
20751pub trait SemanticsProvider {
20752    fn hover(
20753        &self,
20754        buffer: &Entity<Buffer>,
20755        position: text::Anchor,
20756        cx: &mut App,
20757    ) -> Option<Task<Vec<project::Hover>>>;
20758
20759    fn inline_values(
20760        &self,
20761        buffer_handle: Entity<Buffer>,
20762        range: Range<text::Anchor>,
20763        cx: &mut App,
20764    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20765
20766    fn inlay_hints(
20767        &self,
20768        buffer_handle: Entity<Buffer>,
20769        range: Range<text::Anchor>,
20770        cx: &mut App,
20771    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20772
20773    fn resolve_inlay_hint(
20774        &self,
20775        hint: InlayHint,
20776        buffer_handle: Entity<Buffer>,
20777        server_id: LanguageServerId,
20778        cx: &mut App,
20779    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20780
20781    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20782
20783    fn document_highlights(
20784        &self,
20785        buffer: &Entity<Buffer>,
20786        position: text::Anchor,
20787        cx: &mut App,
20788    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20789
20790    fn definitions(
20791        &self,
20792        buffer: &Entity<Buffer>,
20793        position: text::Anchor,
20794        kind: GotoDefinitionKind,
20795        cx: &mut App,
20796    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20797
20798    fn range_for_rename(
20799        &self,
20800        buffer: &Entity<Buffer>,
20801        position: text::Anchor,
20802        cx: &mut App,
20803    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20804
20805    fn perform_rename(
20806        &self,
20807        buffer: &Entity<Buffer>,
20808        position: text::Anchor,
20809        new_name: String,
20810        cx: &mut App,
20811    ) -> Option<Task<Result<ProjectTransaction>>>;
20812
20813    fn pull_diagnostics_for_buffer(
20814        &self,
20815        buffer: Entity<Buffer>,
20816        cx: &mut App,
20817    ) -> Task<anyhow::Result<()>>;
20818}
20819
20820pub trait CompletionProvider {
20821    fn completions(
20822        &self,
20823        excerpt_id: ExcerptId,
20824        buffer: &Entity<Buffer>,
20825        buffer_position: text::Anchor,
20826        trigger: CompletionContext,
20827        window: &mut Window,
20828        cx: &mut Context<Editor>,
20829    ) -> Task<Result<Vec<CompletionResponse>>>;
20830
20831    fn resolve_completions(
20832        &self,
20833        _buffer: Entity<Buffer>,
20834        _completion_indices: Vec<usize>,
20835        _completions: Rc<RefCell<Box<[Completion]>>>,
20836        _cx: &mut Context<Editor>,
20837    ) -> Task<Result<bool>> {
20838        Task::ready(Ok(false))
20839    }
20840
20841    fn apply_additional_edits_for_completion(
20842        &self,
20843        _buffer: Entity<Buffer>,
20844        _completions: Rc<RefCell<Box<[Completion]>>>,
20845        _completion_index: usize,
20846        _push_to_history: bool,
20847        _cx: &mut Context<Editor>,
20848    ) -> Task<Result<Option<language::Transaction>>> {
20849        Task::ready(Ok(None))
20850    }
20851
20852    fn is_completion_trigger(
20853        &self,
20854        buffer: &Entity<Buffer>,
20855        position: language::Anchor,
20856        text: &str,
20857        trigger_in_words: bool,
20858        menu_is_open: bool,
20859        cx: &mut Context<Editor>,
20860    ) -> bool;
20861
20862    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20863
20864    fn sort_completions(&self) -> bool {
20865        true
20866    }
20867
20868    fn filter_completions(&self) -> bool {
20869        true
20870    }
20871}
20872
20873pub trait CodeActionProvider {
20874    fn id(&self) -> Arc<str>;
20875
20876    fn code_actions(
20877        &self,
20878        buffer: &Entity<Buffer>,
20879        range: Range<text::Anchor>,
20880        window: &mut Window,
20881        cx: &mut App,
20882    ) -> Task<Result<Vec<CodeAction>>>;
20883
20884    fn apply_code_action(
20885        &self,
20886        buffer_handle: Entity<Buffer>,
20887        action: CodeAction,
20888        excerpt_id: ExcerptId,
20889        push_to_history: bool,
20890        window: &mut Window,
20891        cx: &mut App,
20892    ) -> Task<Result<ProjectTransaction>>;
20893}
20894
20895impl CodeActionProvider for Entity<Project> {
20896    fn id(&self) -> Arc<str> {
20897        "project".into()
20898    }
20899
20900    fn code_actions(
20901        &self,
20902        buffer: &Entity<Buffer>,
20903        range: Range<text::Anchor>,
20904        _window: &mut Window,
20905        cx: &mut App,
20906    ) -> Task<Result<Vec<CodeAction>>> {
20907        self.update(cx, |project, cx| {
20908            let code_lens = project.code_lens(buffer, range.clone(), cx);
20909            let code_actions = project.code_actions(buffer, range, None, cx);
20910            cx.background_spawn(async move {
20911                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20912                Ok(code_lens
20913                    .context("code lens fetch")?
20914                    .into_iter()
20915                    .chain(code_actions.context("code action fetch")?)
20916                    .collect())
20917            })
20918        })
20919    }
20920
20921    fn apply_code_action(
20922        &self,
20923        buffer_handle: Entity<Buffer>,
20924        action: CodeAction,
20925        _excerpt_id: ExcerptId,
20926        push_to_history: bool,
20927        _window: &mut Window,
20928        cx: &mut App,
20929    ) -> Task<Result<ProjectTransaction>> {
20930        self.update(cx, |project, cx| {
20931            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20932        })
20933    }
20934}
20935
20936fn snippet_completions(
20937    project: &Project,
20938    buffer: &Entity<Buffer>,
20939    buffer_position: text::Anchor,
20940    cx: &mut App,
20941) -> Task<Result<CompletionResponse>> {
20942    let languages = buffer.read(cx).languages_at(buffer_position);
20943    let snippet_store = project.snippets().read(cx);
20944
20945    let scopes: Vec<_> = languages
20946        .iter()
20947        .filter_map(|language| {
20948            let language_name = language.lsp_id();
20949            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20950
20951            if snippets.is_empty() {
20952                None
20953            } else {
20954                Some((language.default_scope(), snippets))
20955            }
20956        })
20957        .collect();
20958
20959    if scopes.is_empty() {
20960        return Task::ready(Ok(CompletionResponse {
20961            completions: vec![],
20962            is_incomplete: false,
20963        }));
20964    }
20965
20966    let snapshot = buffer.read(cx).text_snapshot();
20967    let chars: String = snapshot
20968        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20969        .collect();
20970    let executor = cx.background_executor().clone();
20971
20972    cx.background_spawn(async move {
20973        let mut is_incomplete = false;
20974        let mut completions: Vec<Completion> = Vec::new();
20975        for (scope, snippets) in scopes.into_iter() {
20976            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20977            let mut last_word = chars
20978                .chars()
20979                .take_while(|c| classifier.is_word(*c))
20980                .collect::<String>();
20981            last_word = last_word.chars().rev().collect();
20982
20983            if last_word.is_empty() {
20984                return Ok(CompletionResponse {
20985                    completions: vec![],
20986                    is_incomplete: true,
20987                });
20988            }
20989
20990            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20991            let to_lsp = |point: &text::Anchor| {
20992                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20993                point_to_lsp(end)
20994            };
20995            let lsp_end = to_lsp(&buffer_position);
20996
20997            let candidates = snippets
20998                .iter()
20999                .enumerate()
21000                .flat_map(|(ix, snippet)| {
21001                    snippet
21002                        .prefix
21003                        .iter()
21004                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21005                })
21006                .collect::<Vec<StringMatchCandidate>>();
21007
21008            const MAX_RESULTS: usize = 100;
21009            let mut matches = fuzzy::match_strings(
21010                &candidates,
21011                &last_word,
21012                last_word.chars().any(|c| c.is_uppercase()),
21013                MAX_RESULTS,
21014                &Default::default(),
21015                executor.clone(),
21016            )
21017            .await;
21018
21019            if matches.len() >= MAX_RESULTS {
21020                is_incomplete = true;
21021            }
21022
21023            // Remove all candidates where the query's start does not match the start of any word in the candidate
21024            if let Some(query_start) = last_word.chars().next() {
21025                matches.retain(|string_match| {
21026                    split_words(&string_match.string).any(|word| {
21027                        // Check that the first codepoint of the word as lowercase matches the first
21028                        // codepoint of the query as lowercase
21029                        word.chars()
21030                            .flat_map(|codepoint| codepoint.to_lowercase())
21031                            .zip(query_start.to_lowercase())
21032                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21033                    })
21034                });
21035            }
21036
21037            let matched_strings = matches
21038                .into_iter()
21039                .map(|m| m.string)
21040                .collect::<HashSet<_>>();
21041
21042            completions.extend(snippets.iter().filter_map(|snippet| {
21043                let matching_prefix = snippet
21044                    .prefix
21045                    .iter()
21046                    .find(|prefix| matched_strings.contains(*prefix))?;
21047                let start = as_offset - last_word.len();
21048                let start = snapshot.anchor_before(start);
21049                let range = start..buffer_position;
21050                let lsp_start = to_lsp(&start);
21051                let lsp_range = lsp::Range {
21052                    start: lsp_start,
21053                    end: lsp_end,
21054                };
21055                Some(Completion {
21056                    replace_range: range,
21057                    new_text: snippet.body.clone(),
21058                    source: CompletionSource::Lsp {
21059                        insert_range: None,
21060                        server_id: LanguageServerId(usize::MAX),
21061                        resolved: true,
21062                        lsp_completion: Box::new(lsp::CompletionItem {
21063                            label: snippet.prefix.first().unwrap().clone(),
21064                            kind: Some(CompletionItemKind::SNIPPET),
21065                            label_details: snippet.description.as_ref().map(|description| {
21066                                lsp::CompletionItemLabelDetails {
21067                                    detail: Some(description.clone()),
21068                                    description: None,
21069                                }
21070                            }),
21071                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21072                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21073                                lsp::InsertReplaceEdit {
21074                                    new_text: snippet.body.clone(),
21075                                    insert: lsp_range,
21076                                    replace: lsp_range,
21077                                },
21078                            )),
21079                            filter_text: Some(snippet.body.clone()),
21080                            sort_text: Some(char::MAX.to_string()),
21081                            ..lsp::CompletionItem::default()
21082                        }),
21083                        lsp_defaults: None,
21084                    },
21085                    label: CodeLabel {
21086                        text: matching_prefix.clone(),
21087                        runs: Vec::new(),
21088                        filter_range: 0..matching_prefix.len(),
21089                    },
21090                    icon_path: None,
21091                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21092                        single_line: snippet.name.clone().into(),
21093                        plain_text: snippet
21094                            .description
21095                            .clone()
21096                            .map(|description| description.into()),
21097                    }),
21098                    insert_text_mode: None,
21099                    confirm: None,
21100                })
21101            }))
21102        }
21103
21104        Ok(CompletionResponse {
21105            completions,
21106            is_incomplete,
21107        })
21108    })
21109}
21110
21111impl CompletionProvider for Entity<Project> {
21112    fn completions(
21113        &self,
21114        _excerpt_id: ExcerptId,
21115        buffer: &Entity<Buffer>,
21116        buffer_position: text::Anchor,
21117        options: CompletionContext,
21118        _window: &mut Window,
21119        cx: &mut Context<Editor>,
21120    ) -> Task<Result<Vec<CompletionResponse>>> {
21121        self.update(cx, |project, cx| {
21122            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21123            let project_completions = project.completions(buffer, buffer_position, options, cx);
21124            cx.background_spawn(async move {
21125                let mut responses = project_completions.await?;
21126                let snippets = snippets.await?;
21127                if !snippets.completions.is_empty() {
21128                    responses.push(snippets);
21129                }
21130                Ok(responses)
21131            })
21132        })
21133    }
21134
21135    fn resolve_completions(
21136        &self,
21137        buffer: Entity<Buffer>,
21138        completion_indices: Vec<usize>,
21139        completions: Rc<RefCell<Box<[Completion]>>>,
21140        cx: &mut Context<Editor>,
21141    ) -> Task<Result<bool>> {
21142        self.update(cx, |project, cx| {
21143            project.lsp_store().update(cx, |lsp_store, cx| {
21144                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21145            })
21146        })
21147    }
21148
21149    fn apply_additional_edits_for_completion(
21150        &self,
21151        buffer: Entity<Buffer>,
21152        completions: Rc<RefCell<Box<[Completion]>>>,
21153        completion_index: usize,
21154        push_to_history: bool,
21155        cx: &mut Context<Editor>,
21156    ) -> Task<Result<Option<language::Transaction>>> {
21157        self.update(cx, |project, cx| {
21158            project.lsp_store().update(cx, |lsp_store, cx| {
21159                lsp_store.apply_additional_edits_for_completion(
21160                    buffer,
21161                    completions,
21162                    completion_index,
21163                    push_to_history,
21164                    cx,
21165                )
21166            })
21167        })
21168    }
21169
21170    fn is_completion_trigger(
21171        &self,
21172        buffer: &Entity<Buffer>,
21173        position: language::Anchor,
21174        text: &str,
21175        trigger_in_words: bool,
21176        menu_is_open: bool,
21177        cx: &mut Context<Editor>,
21178    ) -> bool {
21179        let mut chars = text.chars();
21180        let char = if let Some(char) = chars.next() {
21181            char
21182        } else {
21183            return false;
21184        };
21185        if chars.next().is_some() {
21186            return false;
21187        }
21188
21189        let buffer = buffer.read(cx);
21190        let snapshot = buffer.snapshot();
21191        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21192            return false;
21193        }
21194        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21195        if trigger_in_words && classifier.is_word(char) {
21196            return true;
21197        }
21198
21199        buffer.completion_triggers().contains(text)
21200    }
21201}
21202
21203impl SemanticsProvider for Entity<Project> {
21204    fn hover(
21205        &self,
21206        buffer: &Entity<Buffer>,
21207        position: text::Anchor,
21208        cx: &mut App,
21209    ) -> Option<Task<Vec<project::Hover>>> {
21210        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21211    }
21212
21213    fn document_highlights(
21214        &self,
21215        buffer: &Entity<Buffer>,
21216        position: text::Anchor,
21217        cx: &mut App,
21218    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21219        Some(self.update(cx, |project, cx| {
21220            project.document_highlights(buffer, position, cx)
21221        }))
21222    }
21223
21224    fn definitions(
21225        &self,
21226        buffer: &Entity<Buffer>,
21227        position: text::Anchor,
21228        kind: GotoDefinitionKind,
21229        cx: &mut App,
21230    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21231        Some(self.update(cx, |project, cx| match kind {
21232            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21233            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21234            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21235            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21236        }))
21237    }
21238
21239    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21240        // TODO: make this work for remote projects
21241        self.update(cx, |project, cx| {
21242            if project
21243                .active_debug_session(cx)
21244                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21245            {
21246                return true;
21247            }
21248
21249            buffer.update(cx, |buffer, cx| {
21250                project.any_language_server_supports_inlay_hints(buffer, cx)
21251            })
21252        })
21253    }
21254
21255    fn inline_values(
21256        &self,
21257        buffer_handle: Entity<Buffer>,
21258
21259        range: Range<text::Anchor>,
21260        cx: &mut App,
21261    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21262        self.update(cx, |project, cx| {
21263            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21264
21265            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21266        })
21267    }
21268
21269    fn inlay_hints(
21270        &self,
21271        buffer_handle: Entity<Buffer>,
21272        range: Range<text::Anchor>,
21273        cx: &mut App,
21274    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21275        Some(self.update(cx, |project, cx| {
21276            project.inlay_hints(buffer_handle, range, cx)
21277        }))
21278    }
21279
21280    fn resolve_inlay_hint(
21281        &self,
21282        hint: InlayHint,
21283        buffer_handle: Entity<Buffer>,
21284        server_id: LanguageServerId,
21285        cx: &mut App,
21286    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21287        Some(self.update(cx, |project, cx| {
21288            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21289        }))
21290    }
21291
21292    fn range_for_rename(
21293        &self,
21294        buffer: &Entity<Buffer>,
21295        position: text::Anchor,
21296        cx: &mut App,
21297    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21298        Some(self.update(cx, |project, cx| {
21299            let buffer = buffer.clone();
21300            let task = project.prepare_rename(buffer.clone(), position, cx);
21301            cx.spawn(async move |_, cx| {
21302                Ok(match task.await? {
21303                    PrepareRenameResponse::Success(range) => Some(range),
21304                    PrepareRenameResponse::InvalidPosition => None,
21305                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21306                        // Fallback on using TreeSitter info to determine identifier range
21307                        buffer.read_with(cx, |buffer, _| {
21308                            let snapshot = buffer.snapshot();
21309                            let (range, kind) = snapshot.surrounding_word(position);
21310                            if kind != Some(CharKind::Word) {
21311                                return None;
21312                            }
21313                            Some(
21314                                snapshot.anchor_before(range.start)
21315                                    ..snapshot.anchor_after(range.end),
21316                            )
21317                        })?
21318                    }
21319                })
21320            })
21321        }))
21322    }
21323
21324    fn perform_rename(
21325        &self,
21326        buffer: &Entity<Buffer>,
21327        position: text::Anchor,
21328        new_name: String,
21329        cx: &mut App,
21330    ) -> Option<Task<Result<ProjectTransaction>>> {
21331        Some(self.update(cx, |project, cx| {
21332            project.perform_rename(buffer.clone(), position, new_name, cx)
21333        }))
21334    }
21335
21336    fn pull_diagnostics_for_buffer(
21337        &self,
21338        buffer: Entity<Buffer>,
21339        cx: &mut App,
21340    ) -> Task<anyhow::Result<()>> {
21341        let diagnostics = self.update(cx, |project, cx| {
21342            project
21343                .lsp_store()
21344                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21345        });
21346        let project = self.clone();
21347        cx.spawn(async move |cx| {
21348            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21349            project.update(cx, |project, cx| {
21350                project.lsp_store().update(cx, |lsp_store, cx| {
21351                    for diagnostics_set in diagnostics {
21352                        let LspPullDiagnostics::Response {
21353                            server_id,
21354                            uri,
21355                            diagnostics,
21356                        } = diagnostics_set
21357                        else {
21358                            continue;
21359                        };
21360
21361                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21362                        let disk_based_sources = adapter
21363                            .as_ref()
21364                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21365                            .unwrap_or(&[]);
21366                        match diagnostics {
21367                            PulledDiagnostics::Unchanged { result_id } => {
21368                                lsp_store
21369                                    .merge_diagnostics(
21370                                        server_id,
21371                                        lsp::PublishDiagnosticsParams {
21372                                            uri: uri.clone(),
21373                                            diagnostics: Vec::new(),
21374                                            version: None,
21375                                        },
21376                                        Some(result_id),
21377                                        DiagnosticSourceKind::Pulled,
21378                                        disk_based_sources,
21379                                        |_, _| true,
21380                                        cx,
21381                                    )
21382                                    .log_err();
21383                            }
21384                            PulledDiagnostics::Changed {
21385                                diagnostics,
21386                                result_id,
21387                            } => {
21388                                lsp_store
21389                                    .merge_diagnostics(
21390                                        server_id,
21391                                        lsp::PublishDiagnosticsParams {
21392                                            uri: uri.clone(),
21393                                            diagnostics,
21394                                            version: None,
21395                                        },
21396                                        result_id,
21397                                        DiagnosticSourceKind::Pulled,
21398                                        disk_based_sources,
21399                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21400                                            DiagnosticSourceKind::Pulled => false,
21401                                            DiagnosticSourceKind::Other
21402                                            | DiagnosticSourceKind::Pushed => true,
21403                                        },
21404                                        cx,
21405                                    )
21406                                    .log_err();
21407                            }
21408                        }
21409                    }
21410                })
21411            })
21412        })
21413    }
21414}
21415
21416fn inlay_hint_settings(
21417    location: Anchor,
21418    snapshot: &MultiBufferSnapshot,
21419    cx: &mut Context<Editor>,
21420) -> InlayHintSettings {
21421    let file = snapshot.file_at(location);
21422    let language = snapshot.language_at(location).map(|l| l.name());
21423    language_settings(language, file, cx).inlay_hints
21424}
21425
21426fn consume_contiguous_rows(
21427    contiguous_row_selections: &mut Vec<Selection<Point>>,
21428    selection: &Selection<Point>,
21429    display_map: &DisplaySnapshot,
21430    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21431) -> (MultiBufferRow, MultiBufferRow) {
21432    contiguous_row_selections.push(selection.clone());
21433    let start_row = MultiBufferRow(selection.start.row);
21434    let mut end_row = ending_row(selection, display_map);
21435
21436    while let Some(next_selection) = selections.peek() {
21437        if next_selection.start.row <= end_row.0 {
21438            end_row = ending_row(next_selection, display_map);
21439            contiguous_row_selections.push(selections.next().unwrap().clone());
21440        } else {
21441            break;
21442        }
21443    }
21444    (start_row, end_row)
21445}
21446
21447fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21448    if next_selection.end.column > 0 || next_selection.is_empty() {
21449        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21450    } else {
21451        MultiBufferRow(next_selection.end.row)
21452    }
21453}
21454
21455impl EditorSnapshot {
21456    pub fn remote_selections_in_range<'a>(
21457        &'a self,
21458        range: &'a Range<Anchor>,
21459        collaboration_hub: &dyn CollaborationHub,
21460        cx: &'a App,
21461    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21462        let participant_names = collaboration_hub.user_names(cx);
21463        let participant_indices = collaboration_hub.user_participant_indices(cx);
21464        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21465        let collaborators_by_replica_id = collaborators_by_peer_id
21466            .values()
21467            .map(|collaborator| (collaborator.replica_id, collaborator))
21468            .collect::<HashMap<_, _>>();
21469        self.buffer_snapshot
21470            .selections_in_range(range, false)
21471            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21472                if replica_id == AGENT_REPLICA_ID {
21473                    Some(RemoteSelection {
21474                        replica_id,
21475                        selection,
21476                        cursor_shape,
21477                        line_mode,
21478                        collaborator_id: CollaboratorId::Agent,
21479                        user_name: Some("Agent".into()),
21480                        color: cx.theme().players().agent(),
21481                    })
21482                } else {
21483                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21484                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21485                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21486                    Some(RemoteSelection {
21487                        replica_id,
21488                        selection,
21489                        cursor_shape,
21490                        line_mode,
21491                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21492                        user_name,
21493                        color: if let Some(index) = participant_index {
21494                            cx.theme().players().color_for_participant(index.0)
21495                        } else {
21496                            cx.theme().players().absent()
21497                        },
21498                    })
21499                }
21500            })
21501    }
21502
21503    pub fn hunks_for_ranges(
21504        &self,
21505        ranges: impl IntoIterator<Item = Range<Point>>,
21506    ) -> Vec<MultiBufferDiffHunk> {
21507        let mut hunks = Vec::new();
21508        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21509            HashMap::default();
21510        for query_range in ranges {
21511            let query_rows =
21512                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21513            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21514                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21515            ) {
21516                // Include deleted hunks that are adjacent to the query range, because
21517                // otherwise they would be missed.
21518                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21519                if hunk.status().is_deleted() {
21520                    intersects_range |= hunk.row_range.start == query_rows.end;
21521                    intersects_range |= hunk.row_range.end == query_rows.start;
21522                }
21523                if intersects_range {
21524                    if !processed_buffer_rows
21525                        .entry(hunk.buffer_id)
21526                        .or_default()
21527                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21528                    {
21529                        continue;
21530                    }
21531                    hunks.push(hunk);
21532                }
21533            }
21534        }
21535
21536        hunks
21537    }
21538
21539    fn display_diff_hunks_for_rows<'a>(
21540        &'a self,
21541        display_rows: Range<DisplayRow>,
21542        folded_buffers: &'a HashSet<BufferId>,
21543    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21544        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21545        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21546
21547        self.buffer_snapshot
21548            .diff_hunks_in_range(buffer_start..buffer_end)
21549            .filter_map(|hunk| {
21550                if folded_buffers.contains(&hunk.buffer_id) {
21551                    return None;
21552                }
21553
21554                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21555                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21556
21557                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21558                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21559
21560                let display_hunk = if hunk_display_start.column() != 0 {
21561                    DisplayDiffHunk::Folded {
21562                        display_row: hunk_display_start.row(),
21563                    }
21564                } else {
21565                    let mut end_row = hunk_display_end.row();
21566                    if hunk_display_end.column() > 0 {
21567                        end_row.0 += 1;
21568                    }
21569                    let is_created_file = hunk.is_created_file();
21570                    DisplayDiffHunk::Unfolded {
21571                        status: hunk.status(),
21572                        diff_base_byte_range: hunk.diff_base_byte_range,
21573                        display_row_range: hunk_display_start.row()..end_row,
21574                        multi_buffer_range: Anchor::range_in_buffer(
21575                            hunk.excerpt_id,
21576                            hunk.buffer_id,
21577                            hunk.buffer_range,
21578                        ),
21579                        is_created_file,
21580                    }
21581                };
21582
21583                Some(display_hunk)
21584            })
21585    }
21586
21587    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21588        self.display_snapshot.buffer_snapshot.language_at(position)
21589    }
21590
21591    pub fn is_focused(&self) -> bool {
21592        self.is_focused
21593    }
21594
21595    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21596        self.placeholder_text.as_ref()
21597    }
21598
21599    pub fn scroll_position(&self) -> gpui::Point<f32> {
21600        self.scroll_anchor.scroll_position(&self.display_snapshot)
21601    }
21602
21603    fn gutter_dimensions(
21604        &self,
21605        font_id: FontId,
21606        font_size: Pixels,
21607        max_line_number_width: Pixels,
21608        cx: &App,
21609    ) -> Option<GutterDimensions> {
21610        if !self.show_gutter {
21611            return None;
21612        }
21613
21614        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21615        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21616
21617        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21618            matches!(
21619                ProjectSettings::get_global(cx).git.git_gutter,
21620                Some(GitGutterSetting::TrackedFiles)
21621            )
21622        });
21623        let gutter_settings = EditorSettings::get_global(cx).gutter;
21624        let show_line_numbers = self
21625            .show_line_numbers
21626            .unwrap_or(gutter_settings.line_numbers);
21627        let line_gutter_width = if show_line_numbers {
21628            // Avoid flicker-like gutter resizes when the line number gains another digit by
21629            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21630            let min_width_for_number_on_gutter =
21631                ch_advance * gutter_settings.min_line_number_digits as f32;
21632            max_line_number_width.max(min_width_for_number_on_gutter)
21633        } else {
21634            0.0.into()
21635        };
21636
21637        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21638        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21639
21640        let git_blame_entries_width =
21641            self.git_blame_gutter_max_author_length
21642                .map(|max_author_length| {
21643                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21644                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21645
21646                    /// The number of characters to dedicate to gaps and margins.
21647                    const SPACING_WIDTH: usize = 4;
21648
21649                    let max_char_count = max_author_length.min(renderer.max_author_length())
21650                        + ::git::SHORT_SHA_LENGTH
21651                        + MAX_RELATIVE_TIMESTAMP.len()
21652                        + SPACING_WIDTH;
21653
21654                    ch_advance * max_char_count
21655                });
21656
21657        let is_singleton = self.buffer_snapshot.is_singleton();
21658
21659        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21660        left_padding += if !is_singleton {
21661            ch_width * 4.0
21662        } else if show_runnables || show_breakpoints {
21663            ch_width * 3.0
21664        } else if show_git_gutter && show_line_numbers {
21665            ch_width * 2.0
21666        } else if show_git_gutter || show_line_numbers {
21667            ch_width
21668        } else {
21669            px(0.)
21670        };
21671
21672        let shows_folds = is_singleton && gutter_settings.folds;
21673
21674        let right_padding = if shows_folds && show_line_numbers {
21675            ch_width * 4.0
21676        } else if shows_folds || (!is_singleton && show_line_numbers) {
21677            ch_width * 3.0
21678        } else if show_line_numbers {
21679            ch_width
21680        } else {
21681            px(0.)
21682        };
21683
21684        Some(GutterDimensions {
21685            left_padding,
21686            right_padding,
21687            width: line_gutter_width + left_padding + right_padding,
21688            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21689            git_blame_entries_width,
21690        })
21691    }
21692
21693    pub fn render_crease_toggle(
21694        &self,
21695        buffer_row: MultiBufferRow,
21696        row_contains_cursor: bool,
21697        editor: Entity<Editor>,
21698        window: &mut Window,
21699        cx: &mut App,
21700    ) -> Option<AnyElement> {
21701        let folded = self.is_line_folded(buffer_row);
21702        let mut is_foldable = false;
21703
21704        if let Some(crease) = self
21705            .crease_snapshot
21706            .query_row(buffer_row, &self.buffer_snapshot)
21707        {
21708            is_foldable = true;
21709            match crease {
21710                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21711                    if let Some(render_toggle) = render_toggle {
21712                        let toggle_callback =
21713                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21714                                if folded {
21715                                    editor.update(cx, |editor, cx| {
21716                                        editor.fold_at(buffer_row, window, cx)
21717                                    });
21718                                } else {
21719                                    editor.update(cx, |editor, cx| {
21720                                        editor.unfold_at(buffer_row, window, cx)
21721                                    });
21722                                }
21723                            });
21724                        return Some((render_toggle)(
21725                            buffer_row,
21726                            folded,
21727                            toggle_callback,
21728                            window,
21729                            cx,
21730                        ));
21731                    }
21732                }
21733            }
21734        }
21735
21736        is_foldable |= self.starts_indent(buffer_row);
21737
21738        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21739            Some(
21740                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21741                    .toggle_state(folded)
21742                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21743                        if folded {
21744                            this.unfold_at(buffer_row, window, cx);
21745                        } else {
21746                            this.fold_at(buffer_row, window, cx);
21747                        }
21748                    }))
21749                    .into_any_element(),
21750            )
21751        } else {
21752            None
21753        }
21754    }
21755
21756    pub fn render_crease_trailer(
21757        &self,
21758        buffer_row: MultiBufferRow,
21759        window: &mut Window,
21760        cx: &mut App,
21761    ) -> Option<AnyElement> {
21762        let folded = self.is_line_folded(buffer_row);
21763        if let Crease::Inline { render_trailer, .. } = self
21764            .crease_snapshot
21765            .query_row(buffer_row, &self.buffer_snapshot)?
21766        {
21767            let render_trailer = render_trailer.as_ref()?;
21768            Some(render_trailer(buffer_row, folded, window, cx))
21769        } else {
21770            None
21771        }
21772    }
21773}
21774
21775impl Deref for EditorSnapshot {
21776    type Target = DisplaySnapshot;
21777
21778    fn deref(&self) -> &Self::Target {
21779        &self.display_snapshot
21780    }
21781}
21782
21783#[derive(Clone, Debug, PartialEq, Eq)]
21784pub enum EditorEvent {
21785    InputIgnored {
21786        text: Arc<str>,
21787    },
21788    InputHandled {
21789        utf16_range_to_replace: Option<Range<isize>>,
21790        text: Arc<str>,
21791    },
21792    ExcerptsAdded {
21793        buffer: Entity<Buffer>,
21794        predecessor: ExcerptId,
21795        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21796    },
21797    ExcerptsRemoved {
21798        ids: Vec<ExcerptId>,
21799        removed_buffer_ids: Vec<BufferId>,
21800    },
21801    BufferFoldToggled {
21802        ids: Vec<ExcerptId>,
21803        folded: bool,
21804    },
21805    ExcerptsEdited {
21806        ids: Vec<ExcerptId>,
21807    },
21808    ExcerptsExpanded {
21809        ids: Vec<ExcerptId>,
21810    },
21811    BufferEdited,
21812    Edited {
21813        transaction_id: clock::Lamport,
21814    },
21815    Reparsed(BufferId),
21816    Focused,
21817    FocusedIn,
21818    Blurred,
21819    DirtyChanged,
21820    Saved,
21821    TitleChanged,
21822    DiffBaseChanged,
21823    SelectionsChanged {
21824        local: bool,
21825    },
21826    ScrollPositionChanged {
21827        local: bool,
21828        autoscroll: bool,
21829    },
21830    Closed,
21831    TransactionUndone {
21832        transaction_id: clock::Lamport,
21833    },
21834    TransactionBegun {
21835        transaction_id: clock::Lamport,
21836    },
21837    Reloaded,
21838    CursorShapeChanged,
21839    PushedToNavHistory {
21840        anchor: Anchor,
21841        is_deactivate: bool,
21842    },
21843}
21844
21845impl EventEmitter<EditorEvent> for Editor {}
21846
21847impl Focusable for Editor {
21848    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21849        self.focus_handle.clone()
21850    }
21851}
21852
21853impl Render for Editor {
21854    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21855        let settings = ThemeSettings::get_global(cx);
21856
21857        let mut text_style = match self.mode {
21858            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21859                color: cx.theme().colors().editor_foreground,
21860                font_family: settings.ui_font.family.clone(),
21861                font_features: settings.ui_font.features.clone(),
21862                font_fallbacks: settings.ui_font.fallbacks.clone(),
21863                font_size: rems(0.875).into(),
21864                font_weight: settings.ui_font.weight,
21865                line_height: relative(settings.buffer_line_height.value()),
21866                ..Default::default()
21867            },
21868            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21869                color: cx.theme().colors().editor_foreground,
21870                font_family: settings.buffer_font.family.clone(),
21871                font_features: settings.buffer_font.features.clone(),
21872                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21873                font_size: settings.buffer_font_size(cx).into(),
21874                font_weight: settings.buffer_font.weight,
21875                line_height: relative(settings.buffer_line_height.value()),
21876                ..Default::default()
21877            },
21878        };
21879        if let Some(text_style_refinement) = &self.text_style_refinement {
21880            text_style.refine(text_style_refinement)
21881        }
21882
21883        let background = match self.mode {
21884            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21885            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21886            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21887            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21888        };
21889
21890        EditorElement::new(
21891            &cx.entity(),
21892            EditorStyle {
21893                background,
21894                local_player: cx.theme().players().local(),
21895                text: text_style,
21896                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21897                syntax: cx.theme().syntax().clone(),
21898                status: cx.theme().status().clone(),
21899                inlay_hints_style: make_inlay_hints_style(cx),
21900                inline_completion_styles: make_suggestion_styles(cx),
21901                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21902                show_underlines: !self.mode.is_minimap(),
21903            },
21904        )
21905    }
21906}
21907
21908impl EntityInputHandler for Editor {
21909    fn text_for_range(
21910        &mut self,
21911        range_utf16: Range<usize>,
21912        adjusted_range: &mut Option<Range<usize>>,
21913        _: &mut Window,
21914        cx: &mut Context<Self>,
21915    ) -> Option<String> {
21916        let snapshot = self.buffer.read(cx).read(cx);
21917        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21918        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21919        if (start.0..end.0) != range_utf16 {
21920            adjusted_range.replace(start.0..end.0);
21921        }
21922        Some(snapshot.text_for_range(start..end).collect())
21923    }
21924
21925    fn selected_text_range(
21926        &mut self,
21927        ignore_disabled_input: bool,
21928        _: &mut Window,
21929        cx: &mut Context<Self>,
21930    ) -> Option<UTF16Selection> {
21931        // Prevent the IME menu from appearing when holding down an alphabetic key
21932        // while input is disabled.
21933        if !ignore_disabled_input && !self.input_enabled {
21934            return None;
21935        }
21936
21937        let selection = self.selections.newest::<OffsetUtf16>(cx);
21938        let range = selection.range();
21939
21940        Some(UTF16Selection {
21941            range: range.start.0..range.end.0,
21942            reversed: selection.reversed,
21943        })
21944    }
21945
21946    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21947        let snapshot = self.buffer.read(cx).read(cx);
21948        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21949        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21950    }
21951
21952    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21953        self.clear_highlights::<InputComposition>(cx);
21954        self.ime_transaction.take();
21955    }
21956
21957    fn replace_text_in_range(
21958        &mut self,
21959        range_utf16: Option<Range<usize>>,
21960        text: &str,
21961        window: &mut Window,
21962        cx: &mut Context<Self>,
21963    ) {
21964        if !self.input_enabled {
21965            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21966            return;
21967        }
21968
21969        self.transact(window, cx, |this, window, cx| {
21970            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21971                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21972                Some(this.selection_replacement_ranges(range_utf16, cx))
21973            } else {
21974                this.marked_text_ranges(cx)
21975            };
21976
21977            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21978                let newest_selection_id = this.selections.newest_anchor().id;
21979                this.selections
21980                    .all::<OffsetUtf16>(cx)
21981                    .iter()
21982                    .zip(ranges_to_replace.iter())
21983                    .find_map(|(selection, range)| {
21984                        if selection.id == newest_selection_id {
21985                            Some(
21986                                (range.start.0 as isize - selection.head().0 as isize)
21987                                    ..(range.end.0 as isize - selection.head().0 as isize),
21988                            )
21989                        } else {
21990                            None
21991                        }
21992                    })
21993            });
21994
21995            cx.emit(EditorEvent::InputHandled {
21996                utf16_range_to_replace: range_to_replace,
21997                text: text.into(),
21998            });
21999
22000            if let Some(new_selected_ranges) = new_selected_ranges {
22001                this.change_selections(None, window, cx, |selections| {
22002                    selections.select_ranges(new_selected_ranges)
22003                });
22004                this.backspace(&Default::default(), window, cx);
22005            }
22006
22007            this.handle_input(text, window, cx);
22008        });
22009
22010        if let Some(transaction) = self.ime_transaction {
22011            self.buffer.update(cx, |buffer, cx| {
22012                buffer.group_until_transaction(transaction, cx);
22013            });
22014        }
22015
22016        self.unmark_text(window, cx);
22017    }
22018
22019    fn replace_and_mark_text_in_range(
22020        &mut self,
22021        range_utf16: Option<Range<usize>>,
22022        text: &str,
22023        new_selected_range_utf16: Option<Range<usize>>,
22024        window: &mut Window,
22025        cx: &mut Context<Self>,
22026    ) {
22027        if !self.input_enabled {
22028            return;
22029        }
22030
22031        let transaction = self.transact(window, cx, |this, window, cx| {
22032            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22033                let snapshot = this.buffer.read(cx).read(cx);
22034                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22035                    for marked_range in &mut marked_ranges {
22036                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22037                        marked_range.start.0 += relative_range_utf16.start;
22038                        marked_range.start =
22039                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22040                        marked_range.end =
22041                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22042                    }
22043                }
22044                Some(marked_ranges)
22045            } else if let Some(range_utf16) = range_utf16 {
22046                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22047                Some(this.selection_replacement_ranges(range_utf16, cx))
22048            } else {
22049                None
22050            };
22051
22052            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22053                let newest_selection_id = this.selections.newest_anchor().id;
22054                this.selections
22055                    .all::<OffsetUtf16>(cx)
22056                    .iter()
22057                    .zip(ranges_to_replace.iter())
22058                    .find_map(|(selection, range)| {
22059                        if selection.id == newest_selection_id {
22060                            Some(
22061                                (range.start.0 as isize - selection.head().0 as isize)
22062                                    ..(range.end.0 as isize - selection.head().0 as isize),
22063                            )
22064                        } else {
22065                            None
22066                        }
22067                    })
22068            });
22069
22070            cx.emit(EditorEvent::InputHandled {
22071                utf16_range_to_replace: range_to_replace,
22072                text: text.into(),
22073            });
22074
22075            if let Some(ranges) = ranges_to_replace {
22076                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22077            }
22078
22079            let marked_ranges = {
22080                let snapshot = this.buffer.read(cx).read(cx);
22081                this.selections
22082                    .disjoint_anchors()
22083                    .iter()
22084                    .map(|selection| {
22085                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22086                    })
22087                    .collect::<Vec<_>>()
22088            };
22089
22090            if text.is_empty() {
22091                this.unmark_text(window, cx);
22092            } else {
22093                this.highlight_text::<InputComposition>(
22094                    marked_ranges.clone(),
22095                    HighlightStyle {
22096                        underline: Some(UnderlineStyle {
22097                            thickness: px(1.),
22098                            color: None,
22099                            wavy: false,
22100                        }),
22101                        ..Default::default()
22102                    },
22103                    cx,
22104                );
22105            }
22106
22107            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22108            let use_autoclose = this.use_autoclose;
22109            let use_auto_surround = this.use_auto_surround;
22110            this.set_use_autoclose(false);
22111            this.set_use_auto_surround(false);
22112            this.handle_input(text, window, cx);
22113            this.set_use_autoclose(use_autoclose);
22114            this.set_use_auto_surround(use_auto_surround);
22115
22116            if let Some(new_selected_range) = new_selected_range_utf16 {
22117                let snapshot = this.buffer.read(cx).read(cx);
22118                let new_selected_ranges = marked_ranges
22119                    .into_iter()
22120                    .map(|marked_range| {
22121                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22122                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22123                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22124                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22125                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22126                    })
22127                    .collect::<Vec<_>>();
22128
22129                drop(snapshot);
22130                this.change_selections(None, window, cx, |selections| {
22131                    selections.select_ranges(new_selected_ranges)
22132                });
22133            }
22134        });
22135
22136        self.ime_transaction = self.ime_transaction.or(transaction);
22137        if let Some(transaction) = self.ime_transaction {
22138            self.buffer.update(cx, |buffer, cx| {
22139                buffer.group_until_transaction(transaction, cx);
22140            });
22141        }
22142
22143        if self.text_highlights::<InputComposition>(cx).is_none() {
22144            self.ime_transaction.take();
22145        }
22146    }
22147
22148    fn bounds_for_range(
22149        &mut self,
22150        range_utf16: Range<usize>,
22151        element_bounds: gpui::Bounds<Pixels>,
22152        window: &mut Window,
22153        cx: &mut Context<Self>,
22154    ) -> Option<gpui::Bounds<Pixels>> {
22155        let text_layout_details = self.text_layout_details(window);
22156        let gpui::Size {
22157            width: em_width,
22158            height: line_height,
22159        } = self.character_size(window);
22160
22161        let snapshot = self.snapshot(window, cx);
22162        let scroll_position = snapshot.scroll_position();
22163        let scroll_left = scroll_position.x * em_width;
22164
22165        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22166        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22167            + self.gutter_dimensions.width
22168            + self.gutter_dimensions.margin;
22169        let y = line_height * (start.row().as_f32() - scroll_position.y);
22170
22171        Some(Bounds {
22172            origin: element_bounds.origin + point(x, y),
22173            size: size(em_width, line_height),
22174        })
22175    }
22176
22177    fn character_index_for_point(
22178        &mut self,
22179        point: gpui::Point<Pixels>,
22180        _window: &mut Window,
22181        _cx: &mut Context<Self>,
22182    ) -> Option<usize> {
22183        let position_map = self.last_position_map.as_ref()?;
22184        if !position_map.text_hitbox.contains(&point) {
22185            return None;
22186        }
22187        let display_point = position_map.point_for_position(point).previous_valid;
22188        let anchor = position_map
22189            .snapshot
22190            .display_point_to_anchor(display_point, Bias::Left);
22191        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22192        Some(utf16_offset.0)
22193    }
22194}
22195
22196trait SelectionExt {
22197    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22198    fn spanned_rows(
22199        &self,
22200        include_end_if_at_line_start: bool,
22201        map: &DisplaySnapshot,
22202    ) -> Range<MultiBufferRow>;
22203}
22204
22205impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22206    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22207        let start = self
22208            .start
22209            .to_point(&map.buffer_snapshot)
22210            .to_display_point(map);
22211        let end = self
22212            .end
22213            .to_point(&map.buffer_snapshot)
22214            .to_display_point(map);
22215        if self.reversed {
22216            end..start
22217        } else {
22218            start..end
22219        }
22220    }
22221
22222    fn spanned_rows(
22223        &self,
22224        include_end_if_at_line_start: bool,
22225        map: &DisplaySnapshot,
22226    ) -> Range<MultiBufferRow> {
22227        let start = self.start.to_point(&map.buffer_snapshot);
22228        let mut end = self.end.to_point(&map.buffer_snapshot);
22229        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22230            end.row -= 1;
22231        }
22232
22233        let buffer_start = map.prev_line_boundary(start).0;
22234        let buffer_end = map.next_line_boundary(end).0;
22235        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22236    }
22237}
22238
22239impl<T: InvalidationRegion> InvalidationStack<T> {
22240    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22241    where
22242        S: Clone + ToOffset,
22243    {
22244        while let Some(region) = self.last() {
22245            let all_selections_inside_invalidation_ranges =
22246                if selections.len() == region.ranges().len() {
22247                    selections
22248                        .iter()
22249                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22250                        .all(|(selection, invalidation_range)| {
22251                            let head = selection.head().to_offset(buffer);
22252                            invalidation_range.start <= head && invalidation_range.end >= head
22253                        })
22254                } else {
22255                    false
22256                };
22257
22258            if all_selections_inside_invalidation_ranges {
22259                break;
22260            } else {
22261                self.pop();
22262            }
22263        }
22264    }
22265}
22266
22267impl<T> Default for InvalidationStack<T> {
22268    fn default() -> Self {
22269        Self(Default::default())
22270    }
22271}
22272
22273impl<T> Deref for InvalidationStack<T> {
22274    type Target = Vec<T>;
22275
22276    fn deref(&self) -> &Self::Target {
22277        &self.0
22278    }
22279}
22280
22281impl<T> DerefMut for InvalidationStack<T> {
22282    fn deref_mut(&mut self) -> &mut Self::Target {
22283        &mut self.0
22284    }
22285}
22286
22287impl InvalidationRegion for SnippetState {
22288    fn ranges(&self) -> &[Range<Anchor>] {
22289        &self.ranges[self.active_index]
22290    }
22291}
22292
22293fn inline_completion_edit_text(
22294    current_snapshot: &BufferSnapshot,
22295    edits: &[(Range<Anchor>, String)],
22296    edit_preview: &EditPreview,
22297    include_deletions: bool,
22298    cx: &App,
22299) -> HighlightedText {
22300    let edits = edits
22301        .iter()
22302        .map(|(anchor, text)| {
22303            (
22304                anchor.start.text_anchor..anchor.end.text_anchor,
22305                text.clone(),
22306            )
22307        })
22308        .collect::<Vec<_>>();
22309
22310    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22311}
22312
22313pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22314    match severity {
22315        lsp::DiagnosticSeverity::ERROR => colors.error,
22316        lsp::DiagnosticSeverity::WARNING => colors.warning,
22317        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22318        lsp::DiagnosticSeverity::HINT => colors.info,
22319        _ => colors.ignored,
22320    }
22321}
22322
22323pub fn styled_runs_for_code_label<'a>(
22324    label: &'a CodeLabel,
22325    syntax_theme: &'a theme::SyntaxTheme,
22326) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22327    let fade_out = HighlightStyle {
22328        fade_out: Some(0.35),
22329        ..Default::default()
22330    };
22331
22332    let mut prev_end = label.filter_range.end;
22333    label
22334        .runs
22335        .iter()
22336        .enumerate()
22337        .flat_map(move |(ix, (range, highlight_id))| {
22338            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22339                style
22340            } else {
22341                return Default::default();
22342            };
22343            let mut muted_style = style;
22344            muted_style.highlight(fade_out);
22345
22346            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22347            if range.start >= label.filter_range.end {
22348                if range.start > prev_end {
22349                    runs.push((prev_end..range.start, fade_out));
22350                }
22351                runs.push((range.clone(), muted_style));
22352            } else if range.end <= label.filter_range.end {
22353                runs.push((range.clone(), style));
22354            } else {
22355                runs.push((range.start..label.filter_range.end, style));
22356                runs.push((label.filter_range.end..range.end, muted_style));
22357            }
22358            prev_end = cmp::max(prev_end, range.end);
22359
22360            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22361                runs.push((prev_end..label.text.len(), fade_out));
22362            }
22363
22364            runs
22365        })
22366}
22367
22368pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22369    let mut prev_index = 0;
22370    let mut prev_codepoint: Option<char> = None;
22371    text.char_indices()
22372        .chain([(text.len(), '\0')])
22373        .filter_map(move |(index, codepoint)| {
22374            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22375            let is_boundary = index == text.len()
22376                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22377                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22378            if is_boundary {
22379                let chunk = &text[prev_index..index];
22380                prev_index = index;
22381                Some(chunk)
22382            } else {
22383                None
22384            }
22385        })
22386}
22387
22388pub trait RangeToAnchorExt: Sized {
22389    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22390
22391    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22392        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22393        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22394    }
22395}
22396
22397impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22398    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22399        let start_offset = self.start.to_offset(snapshot);
22400        let end_offset = self.end.to_offset(snapshot);
22401        if start_offset == end_offset {
22402            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22403        } else {
22404            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22405        }
22406    }
22407}
22408
22409pub trait RowExt {
22410    fn as_f32(&self) -> f32;
22411
22412    fn next_row(&self) -> Self;
22413
22414    fn previous_row(&self) -> Self;
22415
22416    fn minus(&self, other: Self) -> u32;
22417}
22418
22419impl RowExt for DisplayRow {
22420    fn as_f32(&self) -> f32 {
22421        self.0 as f32
22422    }
22423
22424    fn next_row(&self) -> Self {
22425        Self(self.0 + 1)
22426    }
22427
22428    fn previous_row(&self) -> Self {
22429        Self(self.0.saturating_sub(1))
22430    }
22431
22432    fn minus(&self, other: Self) -> u32 {
22433        self.0 - other.0
22434    }
22435}
22436
22437impl RowExt for MultiBufferRow {
22438    fn as_f32(&self) -> f32 {
22439        self.0 as f32
22440    }
22441
22442    fn next_row(&self) -> Self {
22443        Self(self.0 + 1)
22444    }
22445
22446    fn previous_row(&self) -> Self {
22447        Self(self.0.saturating_sub(1))
22448    }
22449
22450    fn minus(&self, other: Self) -> u32 {
22451        self.0 - other.0
22452    }
22453}
22454
22455trait RowRangeExt {
22456    type Row;
22457
22458    fn len(&self) -> usize;
22459
22460    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22461}
22462
22463impl RowRangeExt for Range<MultiBufferRow> {
22464    type Row = MultiBufferRow;
22465
22466    fn len(&self) -> usize {
22467        (self.end.0 - self.start.0) as usize
22468    }
22469
22470    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22471        (self.start.0..self.end.0).map(MultiBufferRow)
22472    }
22473}
22474
22475impl RowRangeExt for Range<DisplayRow> {
22476    type Row = DisplayRow;
22477
22478    fn len(&self) -> usize {
22479        (self.end.0 - self.start.0) as usize
22480    }
22481
22482    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22483        (self.start.0..self.end.0).map(DisplayRow)
22484    }
22485}
22486
22487/// If select range has more than one line, we
22488/// just point the cursor to range.start.
22489fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22490    if range.start.row == range.end.row {
22491        range
22492    } else {
22493        range.start..range.start
22494    }
22495}
22496pub struct KillRing(ClipboardItem);
22497impl Global for KillRing {}
22498
22499const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22500
22501enum BreakpointPromptEditAction {
22502    Log,
22503    Condition,
22504    HitCondition,
22505}
22506
22507struct BreakpointPromptEditor {
22508    pub(crate) prompt: Entity<Editor>,
22509    editor: WeakEntity<Editor>,
22510    breakpoint_anchor: Anchor,
22511    breakpoint: Breakpoint,
22512    edit_action: BreakpointPromptEditAction,
22513    block_ids: HashSet<CustomBlockId>,
22514    editor_margins: Arc<Mutex<EditorMargins>>,
22515    _subscriptions: Vec<Subscription>,
22516}
22517
22518impl BreakpointPromptEditor {
22519    const MAX_LINES: u8 = 4;
22520
22521    fn new(
22522        editor: WeakEntity<Editor>,
22523        breakpoint_anchor: Anchor,
22524        breakpoint: Breakpoint,
22525        edit_action: BreakpointPromptEditAction,
22526        window: &mut Window,
22527        cx: &mut Context<Self>,
22528    ) -> Self {
22529        let base_text = match edit_action {
22530            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22531            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22532            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22533        }
22534        .map(|msg| msg.to_string())
22535        .unwrap_or_default();
22536
22537        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22538        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22539
22540        let prompt = cx.new(|cx| {
22541            let mut prompt = Editor::new(
22542                EditorMode::AutoHeight {
22543                    max_lines: Self::MAX_LINES as usize,
22544                },
22545                buffer,
22546                None,
22547                window,
22548                cx,
22549            );
22550            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22551            prompt.set_show_cursor_when_unfocused(false, cx);
22552            prompt.set_placeholder_text(
22553                match edit_action {
22554                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22555                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22556                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22557                },
22558                cx,
22559            );
22560
22561            prompt
22562        });
22563
22564        Self {
22565            prompt,
22566            editor,
22567            breakpoint_anchor,
22568            breakpoint,
22569            edit_action,
22570            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22571            block_ids: Default::default(),
22572            _subscriptions: vec![],
22573        }
22574    }
22575
22576    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22577        self.block_ids.extend(block_ids)
22578    }
22579
22580    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22581        if let Some(editor) = self.editor.upgrade() {
22582            let message = self
22583                .prompt
22584                .read(cx)
22585                .buffer
22586                .read(cx)
22587                .as_singleton()
22588                .expect("A multi buffer in breakpoint prompt isn't possible")
22589                .read(cx)
22590                .as_rope()
22591                .to_string();
22592
22593            editor.update(cx, |editor, cx| {
22594                editor.edit_breakpoint_at_anchor(
22595                    self.breakpoint_anchor,
22596                    self.breakpoint.clone(),
22597                    match self.edit_action {
22598                        BreakpointPromptEditAction::Log => {
22599                            BreakpointEditAction::EditLogMessage(message.into())
22600                        }
22601                        BreakpointPromptEditAction::Condition => {
22602                            BreakpointEditAction::EditCondition(message.into())
22603                        }
22604                        BreakpointPromptEditAction::HitCondition => {
22605                            BreakpointEditAction::EditHitCondition(message.into())
22606                        }
22607                    },
22608                    cx,
22609                );
22610
22611                editor.remove_blocks(self.block_ids.clone(), None, cx);
22612                cx.focus_self(window);
22613            });
22614        }
22615    }
22616
22617    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22618        self.editor
22619            .update(cx, |editor, cx| {
22620                editor.remove_blocks(self.block_ids.clone(), None, cx);
22621                window.focus(&editor.focus_handle);
22622            })
22623            .log_err();
22624    }
22625
22626    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22627        let settings = ThemeSettings::get_global(cx);
22628        let text_style = TextStyle {
22629            color: if self.prompt.read(cx).read_only(cx) {
22630                cx.theme().colors().text_disabled
22631            } else {
22632                cx.theme().colors().text
22633            },
22634            font_family: settings.buffer_font.family.clone(),
22635            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22636            font_size: settings.buffer_font_size(cx).into(),
22637            font_weight: settings.buffer_font.weight,
22638            line_height: relative(settings.buffer_line_height.value()),
22639            ..Default::default()
22640        };
22641        EditorElement::new(
22642            &self.prompt,
22643            EditorStyle {
22644                background: cx.theme().colors().editor_background,
22645                local_player: cx.theme().players().local(),
22646                text: text_style,
22647                ..Default::default()
22648            },
22649        )
22650    }
22651}
22652
22653impl Render for BreakpointPromptEditor {
22654    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22655        let editor_margins = *self.editor_margins.lock();
22656        let gutter_dimensions = editor_margins.gutter;
22657        h_flex()
22658            .key_context("Editor")
22659            .bg(cx.theme().colors().editor_background)
22660            .border_y_1()
22661            .border_color(cx.theme().status().info_border)
22662            .size_full()
22663            .py(window.line_height() / 2.5)
22664            .on_action(cx.listener(Self::confirm))
22665            .on_action(cx.listener(Self::cancel))
22666            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22667            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22668    }
22669}
22670
22671impl Focusable for BreakpointPromptEditor {
22672    fn focus_handle(&self, cx: &App) -> FocusHandle {
22673        self.prompt.focus_handle(cx)
22674    }
22675}
22676
22677fn all_edits_insertions_or_deletions(
22678    edits: &Vec<(Range<Anchor>, String)>,
22679    snapshot: &MultiBufferSnapshot,
22680) -> bool {
22681    let mut all_insertions = true;
22682    let mut all_deletions = true;
22683
22684    for (range, new_text) in edits.iter() {
22685        let range_is_empty = range.to_offset(&snapshot).is_empty();
22686        let text_is_empty = new_text.is_empty();
22687
22688        if range_is_empty != text_is_empty {
22689            if range_is_empty {
22690                all_deletions = false;
22691            } else {
22692                all_insertions = false;
22693            }
22694        } else {
22695            return false;
22696        }
22697
22698        if !all_insertions && !all_deletions {
22699            return false;
22700        }
22701    }
22702    all_insertions || all_deletions
22703}
22704
22705struct MissingEditPredictionKeybindingTooltip;
22706
22707impl Render for MissingEditPredictionKeybindingTooltip {
22708    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22709        ui::tooltip_container(window, cx, |container, _, cx| {
22710            container
22711                .flex_shrink_0()
22712                .max_w_80()
22713                .min_h(rems_from_px(124.))
22714                .justify_between()
22715                .child(
22716                    v_flex()
22717                        .flex_1()
22718                        .text_ui_sm(cx)
22719                        .child(Label::new("Conflict with Accept Keybinding"))
22720                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22721                )
22722                .child(
22723                    h_flex()
22724                        .pb_1()
22725                        .gap_1()
22726                        .items_end()
22727                        .w_full()
22728                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22729                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22730                        }))
22731                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22732                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22733                        })),
22734                )
22735        })
22736    }
22737}
22738
22739#[derive(Debug, Clone, Copy, PartialEq)]
22740pub struct LineHighlight {
22741    pub background: Background,
22742    pub border: Option<gpui::Hsla>,
22743    pub include_gutter: bool,
22744    pub type_id: Option<TypeId>,
22745}
22746
22747fn render_diff_hunk_controls(
22748    row: u32,
22749    status: &DiffHunkStatus,
22750    hunk_range: Range<Anchor>,
22751    is_created_file: bool,
22752    line_height: Pixels,
22753    editor: &Entity<Editor>,
22754    _window: &mut Window,
22755    cx: &mut App,
22756) -> AnyElement {
22757    h_flex()
22758        .h(line_height)
22759        .mr_1()
22760        .gap_1()
22761        .px_0p5()
22762        .pb_1()
22763        .border_x_1()
22764        .border_b_1()
22765        .border_color(cx.theme().colors().border_variant)
22766        .rounded_b_lg()
22767        .bg(cx.theme().colors().editor_background)
22768        .gap_1()
22769        .block_mouse_except_scroll()
22770        .shadow_md()
22771        .child(if status.has_secondary_hunk() {
22772            Button::new(("stage", row as u64), "Stage")
22773                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22774                .tooltip({
22775                    let focus_handle = editor.focus_handle(cx);
22776                    move |window, cx| {
22777                        Tooltip::for_action_in(
22778                            "Stage Hunk",
22779                            &::git::ToggleStaged,
22780                            &focus_handle,
22781                            window,
22782                            cx,
22783                        )
22784                    }
22785                })
22786                .on_click({
22787                    let editor = editor.clone();
22788                    move |_event, _window, cx| {
22789                        editor.update(cx, |editor, cx| {
22790                            editor.stage_or_unstage_diff_hunks(
22791                                true,
22792                                vec![hunk_range.start..hunk_range.start],
22793                                cx,
22794                            );
22795                        });
22796                    }
22797                })
22798        } else {
22799            Button::new(("unstage", row as u64), "Unstage")
22800                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22801                .tooltip({
22802                    let focus_handle = editor.focus_handle(cx);
22803                    move |window, cx| {
22804                        Tooltip::for_action_in(
22805                            "Unstage Hunk",
22806                            &::git::ToggleStaged,
22807                            &focus_handle,
22808                            window,
22809                            cx,
22810                        )
22811                    }
22812                })
22813                .on_click({
22814                    let editor = editor.clone();
22815                    move |_event, _window, cx| {
22816                        editor.update(cx, |editor, cx| {
22817                            editor.stage_or_unstage_diff_hunks(
22818                                false,
22819                                vec![hunk_range.start..hunk_range.start],
22820                                cx,
22821                            );
22822                        });
22823                    }
22824                })
22825        })
22826        .child(
22827            Button::new(("restore", row as u64), "Restore")
22828                .tooltip({
22829                    let focus_handle = editor.focus_handle(cx);
22830                    move |window, cx| {
22831                        Tooltip::for_action_in(
22832                            "Restore Hunk",
22833                            &::git::Restore,
22834                            &focus_handle,
22835                            window,
22836                            cx,
22837                        )
22838                    }
22839                })
22840                .on_click({
22841                    let editor = editor.clone();
22842                    move |_event, window, cx| {
22843                        editor.update(cx, |editor, cx| {
22844                            let snapshot = editor.snapshot(window, cx);
22845                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22846                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22847                        });
22848                    }
22849                })
22850                .disabled(is_created_file),
22851        )
22852        .when(
22853            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22854            |el| {
22855                el.child(
22856                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22857                        .shape(IconButtonShape::Square)
22858                        .icon_size(IconSize::Small)
22859                        // .disabled(!has_multiple_hunks)
22860                        .tooltip({
22861                            let focus_handle = editor.focus_handle(cx);
22862                            move |window, cx| {
22863                                Tooltip::for_action_in(
22864                                    "Next Hunk",
22865                                    &GoToHunk,
22866                                    &focus_handle,
22867                                    window,
22868                                    cx,
22869                                )
22870                            }
22871                        })
22872                        .on_click({
22873                            let editor = editor.clone();
22874                            move |_event, window, cx| {
22875                                editor.update(cx, |editor, cx| {
22876                                    let snapshot = editor.snapshot(window, cx);
22877                                    let position =
22878                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22879                                    editor.go_to_hunk_before_or_after_position(
22880                                        &snapshot,
22881                                        position,
22882                                        Direction::Next,
22883                                        window,
22884                                        cx,
22885                                    );
22886                                    editor.expand_selected_diff_hunks(cx);
22887                                });
22888                            }
22889                        }),
22890                )
22891                .child(
22892                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22893                        .shape(IconButtonShape::Square)
22894                        .icon_size(IconSize::Small)
22895                        // .disabled(!has_multiple_hunks)
22896                        .tooltip({
22897                            let focus_handle = editor.focus_handle(cx);
22898                            move |window, cx| {
22899                                Tooltip::for_action_in(
22900                                    "Previous Hunk",
22901                                    &GoToPreviousHunk,
22902                                    &focus_handle,
22903                                    window,
22904                                    cx,
22905                                )
22906                            }
22907                        })
22908                        .on_click({
22909                            let editor = editor.clone();
22910                            move |_event, window, cx| {
22911                                editor.update(cx, |editor, cx| {
22912                                    let snapshot = editor.snapshot(window, cx);
22913                                    let point =
22914                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22915                                    editor.go_to_hunk_before_or_after_position(
22916                                        &snapshot,
22917                                        point,
22918                                        Direction::Prev,
22919                                        window,
22920                                        cx,
22921                                    );
22922                                    editor.expand_selected_diff_hunks(cx);
22923                                });
22924                            }
22925                        }),
22926                )
22927            },
22928        )
22929        .into_any_element()
22930}