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        min_lines: usize,
  479        max_lines: usize,
  480    },
  481    Full {
  482        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  483        scale_ui_elements_with_buffer_font_size: bool,
  484        /// When set to `true`, the editor will render a background for the active line.
  485        show_active_line_background: bool,
  486        /// When set to `true`, the editor's height will be determined by its content.
  487        sized_by_content: bool,
  488    },
  489    Minimap {
  490        parent: WeakEntity<Editor>,
  491    },
  492}
  493
  494impl EditorMode {
  495    pub fn full() -> Self {
  496        Self::Full {
  497            scale_ui_elements_with_buffer_font_size: true,
  498            show_active_line_background: true,
  499            sized_by_content: false,
  500        }
  501    }
  502
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    fn is_minimap(&self) -> bool {
  508        matches!(self, Self::Minimap { .. })
  509    }
  510}
  511
  512#[derive(Copy, Clone, Debug)]
  513pub enum SoftWrap {
  514    /// Prefer not to wrap at all.
  515    ///
  516    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  517    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  518    GitDiff,
  519    /// Prefer a single line generally, unless an overly long line is encountered.
  520    None,
  521    /// Soft wrap lines that exceed the editor width.
  522    EditorWidth,
  523    /// Soft wrap lines at the preferred line length.
  524    Column(u32),
  525    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  526    Bounded(u32),
  527}
  528
  529#[derive(Clone)]
  530pub struct EditorStyle {
  531    pub background: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub inline_completion_styles: InlineCompletionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            local_player: PlayerColor::default(),
  548            text: TextStyle::default(),
  549            scrollbar_width: Pixels::default(),
  550            syntax: Default::default(),
  551            // HACK: Status colors don't have a real default.
  552            // We should look into removing the status colors from the editor
  553            // style and retrieve them directly from the theme.
  554            status: StatusColors::dark(),
  555            inlay_hints_style: HighlightStyle::default(),
  556            inline_completion_styles: InlineCompletionStyles {
  557                insertion: HighlightStyle::default(),
  558                whitespace: HighlightStyle::default(),
  559            },
  560            unnecessary_code_fade: Default::default(),
  561            show_underlines: true,
  562        }
  563    }
  564}
  565
  566pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  567    let show_background = language_settings::language_settings(None, None, cx)
  568        .inlay_hints
  569        .show_background;
  570
  571    HighlightStyle {
  572        color: Some(cx.theme().status().hint),
  573        background_color: show_background.then(|| cx.theme().status().hint_background),
  574        ..HighlightStyle::default()
  575    }
  576}
  577
  578pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  579    InlineCompletionStyles {
  580        insertion: HighlightStyle {
  581            color: Some(cx.theme().status().predictive),
  582            ..HighlightStyle::default()
  583        },
  584        whitespace: HighlightStyle {
  585            background_color: Some(cx.theme().status().created_background),
  586            ..HighlightStyle::default()
  587        },
  588    }
  589}
  590
  591type CompletionId = usize;
  592
  593pub(crate) enum EditDisplayMode {
  594    TabAccept,
  595    DiffPopover,
  596    Inline,
  597}
  598
  599enum InlineCompletion {
  600    Edit {
  601        edits: Vec<(Range<Anchor>, String)>,
  602        edit_preview: Option<EditPreview>,
  603        display_mode: EditDisplayMode,
  604        snapshot: BufferSnapshot,
  605    },
  606    Move {
  607        target: Anchor,
  608        snapshot: BufferSnapshot,
  609    },
  610}
  611
  612struct InlineCompletionState {
  613    inlay_ids: Vec<InlayId>,
  614    completion: InlineCompletion,
  615    completion_id: Option<SharedString>,
  616    invalidation_range: Range<Anchor>,
  617}
  618
  619enum EditPredictionSettings {
  620    Disabled,
  621    Enabled {
  622        show_in_menu: bool,
  623        preview_requires_modifier: bool,
  624    },
  625}
  626
  627enum InlineCompletionHighlight {}
  628
  629#[derive(Debug, Clone)]
  630struct InlineDiagnostic {
  631    message: SharedString,
  632    group_id: usize,
  633    is_primary: bool,
  634    start: Point,
  635    severity: lsp::DiagnosticSeverity,
  636}
  637
  638pub enum MenuInlineCompletionsPolicy {
  639    Never,
  640    ByProvider,
  641}
  642
  643pub enum EditPredictionPreview {
  644    /// Modifier is not pressed
  645    Inactive { released_too_fast: bool },
  646    /// Modifier pressed
  647    Active {
  648        since: Instant,
  649        previous_scroll_position: Option<ScrollAnchor>,
  650    },
  651}
  652
  653impl EditPredictionPreview {
  654    pub fn released_too_fast(&self) -> bool {
  655        match self {
  656            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  657            EditPredictionPreview::Active { .. } => false,
  658        }
  659    }
  660
  661    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  662        if let EditPredictionPreview::Active {
  663            previous_scroll_position,
  664            ..
  665        } = self
  666        {
  667            *previous_scroll_position = scroll_position;
  668        }
  669    }
  670}
  671
  672pub struct ContextMenuOptions {
  673    pub min_entries_visible: usize,
  674    pub max_entries_visible: usize,
  675    pub placement: Option<ContextMenuPlacement>,
  676}
  677
  678#[derive(Debug, Clone, PartialEq, Eq)]
  679pub enum ContextMenuPlacement {
  680    Above,
  681    Below,
  682}
  683
  684#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  685struct EditorActionId(usize);
  686
  687impl EditorActionId {
  688    pub fn post_inc(&mut self) -> Self {
  689        let answer = self.0;
  690
  691        *self = Self(answer + 1);
  692
  693        Self(answer)
  694    }
  695}
  696
  697// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  698// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  699
  700type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  701type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  702
  703#[derive(Default)]
  704struct ScrollbarMarkerState {
  705    scrollbar_size: Size<Pixels>,
  706    dirty: bool,
  707    markers: Arc<[PaintQuad]>,
  708    pending_refresh: Option<Task<Result<()>>>,
  709}
  710
  711impl ScrollbarMarkerState {
  712    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  713        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  714    }
  715}
  716
  717#[derive(Clone, Copy, PartialEq, Eq)]
  718pub enum MinimapVisibility {
  719    Disabled,
  720    Enabled {
  721        /// The configuration currently present in the users settings.
  722        setting_configuration: bool,
  723        /// Whether to override the currently set visibility from the users setting.
  724        toggle_override: bool,
  725    },
  726}
  727
  728impl MinimapVisibility {
  729    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  730        if mode.is_full() {
  731            Self::Enabled {
  732                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  733                toggle_override: false,
  734            }
  735        } else {
  736            Self::Disabled
  737        }
  738    }
  739
  740    fn hidden(&self) -> Self {
  741        match *self {
  742            Self::Enabled {
  743                setting_configuration,
  744                ..
  745            } => Self::Enabled {
  746                setting_configuration,
  747                toggle_override: setting_configuration,
  748            },
  749            Self::Disabled => Self::Disabled,
  750        }
  751    }
  752
  753    fn disabled(&self) -> bool {
  754        match *self {
  755            Self::Disabled => true,
  756            _ => false,
  757        }
  758    }
  759
  760    fn settings_visibility(&self) -> bool {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => setting_configuration,
  766            _ => false,
  767        }
  768    }
  769
  770    fn visible(&self) -> bool {
  771        match *self {
  772            Self::Enabled {
  773                setting_configuration,
  774                toggle_override,
  775            } => setting_configuration ^ toggle_override,
  776            _ => false,
  777        }
  778    }
  779
  780    fn toggle_visibility(&self) -> Self {
  781        match *self {
  782            Self::Enabled {
  783                toggle_override,
  784                setting_configuration,
  785            } => Self::Enabled {
  786                setting_configuration,
  787                toggle_override: !toggle_override,
  788            },
  789            Self::Disabled => Self::Disabled,
  790        }
  791    }
  792}
  793
  794#[derive(Clone, Debug)]
  795struct RunnableTasks {
  796    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  797    offset: multi_buffer::Anchor,
  798    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  799    column: u32,
  800    // Values of all named captures, including those starting with '_'
  801    extra_variables: HashMap<String, String>,
  802    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  803    context_range: Range<BufferOffset>,
  804}
  805
  806impl RunnableTasks {
  807    fn resolve<'a>(
  808        &'a self,
  809        cx: &'a task::TaskContext,
  810    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  811        self.templates.iter().filter_map(|(kind, template)| {
  812            template
  813                .resolve_task(&kind.to_id_base(), cx)
  814                .map(|task| (kind.clone(), task))
  815        })
  816    }
  817}
  818
  819#[derive(Clone)]
  820pub struct ResolvedTasks {
  821    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  822    position: Anchor,
  823}
  824
  825#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  826struct BufferOffset(usize);
  827
  828// Addons allow storing per-editor state in other crates (e.g. Vim)
  829pub trait Addon: 'static {
  830    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  831
  832    fn render_buffer_header_controls(
  833        &self,
  834        _: &ExcerptInfo,
  835        _: &Window,
  836        _: &App,
  837    ) -> Option<AnyElement> {
  838        None
  839    }
  840
  841    fn to_any(&self) -> &dyn std::any::Any;
  842
  843    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  844        None
  845    }
  846}
  847
  848/// A set of caret positions, registered when the editor was edited.
  849pub struct ChangeList {
  850    changes: Vec<Vec<Anchor>>,
  851    /// Currently "selected" change.
  852    position: Option<usize>,
  853}
  854
  855impl ChangeList {
  856    pub fn new() -> Self {
  857        Self {
  858            changes: Vec::new(),
  859            position: None,
  860        }
  861    }
  862
  863    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  864    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  865    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  866        if self.changes.is_empty() {
  867            return None;
  868        }
  869
  870        let prev = self.position.unwrap_or(self.changes.len());
  871        let next = if direction == Direction::Prev {
  872            prev.saturating_sub(count)
  873        } else {
  874            (prev + count).min(self.changes.len() - 1)
  875        };
  876        self.position = Some(next);
  877        self.changes.get(next).map(|anchors| anchors.as_slice())
  878    }
  879
  880    /// Adds a new change to the list, resetting the change list position.
  881    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  882        self.position.take();
  883        if pop_state {
  884            self.changes.pop();
  885        }
  886        self.changes.push(new_positions.clone());
  887    }
  888
  889    pub fn last(&self) -> Option<&[Anchor]> {
  890        self.changes.last().map(|anchors| anchors.as_slice())
  891    }
  892}
  893
  894#[derive(Clone)]
  895struct InlineBlamePopoverState {
  896    scroll_handle: ScrollHandle,
  897    commit_message: Option<ParsedCommitMessage>,
  898    markdown: Entity<Markdown>,
  899}
  900
  901struct InlineBlamePopover {
  902    position: gpui::Point<Pixels>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908enum SelectionDragState {
  909    /// State when no drag related activity is detected.
  910    None,
  911    /// State when the mouse is down on a selection that is about to be dragged.
  912    ReadyToDrag {
  913        selection: Selection<Anchor>,
  914        click_position: gpui::Point<Pixels>,
  915        mouse_down_time: Instant,
  916    },
  917    /// State when the mouse is dragging the selection in the editor.
  918    Dragging {
  919        selection: Selection<Anchor>,
  920        drop_cursor: Selection<Anchor>,
  921        hide_drop_cursor: bool,
  922    },
  923}
  924
  925/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  926/// a breakpoint on them.
  927#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  928struct PhantomBreakpointIndicator {
  929    display_row: DisplayRow,
  930    /// There's a small debounce between hovering over the line and showing the indicator.
  931    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  932    is_active: bool,
  933    collides_with_existing_breakpoint: bool,
  934}
  935
  936/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  937///
  938/// See the [module level documentation](self) for more information.
  939pub struct Editor {
  940    focus_handle: FocusHandle,
  941    last_focused_descendant: Option<WeakFocusHandle>,
  942    /// The text buffer being edited
  943    buffer: Entity<MultiBuffer>,
  944    /// Map of how text in the buffer should be displayed.
  945    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  946    pub display_map: Entity<DisplayMap>,
  947    pub selections: SelectionsCollection,
  948    pub scroll_manager: ScrollManager,
  949    /// When inline assist editors are linked, they all render cursors because
  950    /// typing enters text into each of them, even the ones that aren't focused.
  951    pub(crate) show_cursor_when_unfocused: bool,
  952    columnar_selection_tail: Option<Anchor>,
  953    columnar_display_point: Option<DisplayPoint>,
  954    add_selections_state: Option<AddSelectionsState>,
  955    select_next_state: Option<SelectNextState>,
  956    select_prev_state: Option<SelectNextState>,
  957    selection_history: SelectionHistory,
  958    defer_selection_effects: bool,
  959    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  960    autoclose_regions: Vec<AutocloseRegion>,
  961    snippet_stack: InvalidationStack<SnippetState>,
  962    select_syntax_node_history: SelectSyntaxNodeHistory,
  963    ime_transaction: Option<TransactionId>,
  964    pub diagnostics_max_severity: DiagnosticSeverity,
  965    active_diagnostics: ActiveDiagnostic,
  966    show_inline_diagnostics: bool,
  967    inline_diagnostics_update: Task<()>,
  968    inline_diagnostics_enabled: bool,
  969    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  970    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  971    hard_wrap: Option<usize>,
  972
  973    // TODO: make this a access method
  974    pub project: Option<Entity<Project>>,
  975    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  976    completion_provider: Option<Rc<dyn CompletionProvider>>,
  977    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  978    blink_manager: Entity<BlinkManager>,
  979    show_cursor_names: bool,
  980    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  981    pub show_local_selections: bool,
  982    mode: EditorMode,
  983    show_breadcrumbs: bool,
  984    show_gutter: bool,
  985    show_scrollbars: ScrollbarAxes,
  986    minimap_visibility: MinimapVisibility,
  987    offset_content: bool,
  988    disable_expand_excerpt_buttons: bool,
  989    show_line_numbers: Option<bool>,
  990    use_relative_line_numbers: Option<bool>,
  991    show_git_diff_gutter: Option<bool>,
  992    show_code_actions: Option<bool>,
  993    show_runnables: Option<bool>,
  994    show_breakpoints: Option<bool>,
  995    show_wrap_guides: Option<bool>,
  996    show_indent_guides: Option<bool>,
  997    placeholder_text: Option<Arc<str>>,
  998    highlight_order: usize,
  999    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1000    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1001    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1002    scrollbar_marker_state: ScrollbarMarkerState,
 1003    active_indent_guides_state: ActiveIndentGuidesState,
 1004    nav_history: Option<ItemNavHistory>,
 1005    context_menu: RefCell<Option<CodeContextMenu>>,
 1006    context_menu_options: Option<ContextMenuOptions>,
 1007    mouse_context_menu: Option<MouseContextMenu>,
 1008    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1009    inline_blame_popover: Option<InlineBlamePopover>,
 1010    inline_blame_popover_show_task: Option<Task<()>>,
 1011    signature_help_state: SignatureHelpState,
 1012    auto_signature_help: Option<bool>,
 1013    find_all_references_task_sources: Vec<Anchor>,
 1014    next_completion_id: CompletionId,
 1015    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1016    code_actions_task: Option<Task<Result<()>>>,
 1017    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1018    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1019    document_highlights_task: Option<Task<()>>,
 1020    linked_editing_range_task: Option<Task<Option<()>>>,
 1021    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1022    pending_rename: Option<RenameState>,
 1023    searchable: bool,
 1024    cursor_shape: CursorShape,
 1025    current_line_highlight: Option<CurrentLineHighlight>,
 1026    collapse_matches: bool,
 1027    autoindent_mode: Option<AutoindentMode>,
 1028    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1029    input_enabled: bool,
 1030    use_modal_editing: bool,
 1031    read_only: bool,
 1032    leader_id: Option<CollaboratorId>,
 1033    remote_id: Option<ViewId>,
 1034    pub hover_state: HoverState,
 1035    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1036    gutter_hovered: bool,
 1037    hovered_link_state: Option<HoveredLinkState>,
 1038    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1039    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1040    active_inline_completion: Option<InlineCompletionState>,
 1041    /// Used to prevent flickering as the user types while the menu is open
 1042    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1043    edit_prediction_settings: EditPredictionSettings,
 1044    inline_completions_hidden_for_vim_mode: bool,
 1045    show_inline_completions_override: Option<bool>,
 1046    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1047    edit_prediction_preview: EditPredictionPreview,
 1048    edit_prediction_indent_conflict: bool,
 1049    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1050    inlay_hint_cache: InlayHintCache,
 1051    next_inlay_id: usize,
 1052    _subscriptions: Vec<Subscription>,
 1053    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1054    gutter_dimensions: GutterDimensions,
 1055    style: Option<EditorStyle>,
 1056    text_style_refinement: Option<TextStyleRefinement>,
 1057    next_editor_action_id: EditorActionId,
 1058    editor_actions: Rc<
 1059        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1060    >,
 1061    use_autoclose: bool,
 1062    use_auto_surround: bool,
 1063    auto_replace_emoji_shortcode: bool,
 1064    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1065    show_git_blame_gutter: bool,
 1066    show_git_blame_inline: bool,
 1067    show_git_blame_inline_delay_task: Option<Task<()>>,
 1068    git_blame_inline_enabled: bool,
 1069    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1070    serialize_dirty_buffers: bool,
 1071    show_selection_menu: Option<bool>,
 1072    blame: Option<Entity<GitBlame>>,
 1073    blame_subscription: Option<Subscription>,
 1074    custom_context_menu: Option<
 1075        Box<
 1076            dyn 'static
 1077                + Fn(
 1078                    &mut Self,
 1079                    DisplayPoint,
 1080                    &mut Window,
 1081                    &mut Context<Self>,
 1082                ) -> Option<Entity<ui::ContextMenu>>,
 1083        >,
 1084    >,
 1085    last_bounds: Option<Bounds<Pixels>>,
 1086    last_position_map: Option<Rc<PositionMap>>,
 1087    expect_bounds_change: Option<Bounds<Pixels>>,
 1088    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1089    tasks_update_task: Option<Task<()>>,
 1090    breakpoint_store: Option<Entity<BreakpointStore>>,
 1091    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1092    hovered_diff_hunk_row: Option<DisplayRow>,
 1093    pull_diagnostics_task: Task<()>,
 1094    in_project_search: bool,
 1095    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1096    breadcrumb_header: Option<String>,
 1097    focused_block: Option<FocusedBlock>,
 1098    next_scroll_position: NextScrollCursorCenterTopBottom,
 1099    addons: HashMap<TypeId, Box<dyn Addon>>,
 1100    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1101    load_diff_task: Option<Shared<Task<()>>>,
 1102    /// Whether we are temporarily displaying a diff other than git's
 1103    temporary_diff_override: bool,
 1104    selection_mark_mode: bool,
 1105    toggle_fold_multiple_buffers: Task<()>,
 1106    _scroll_cursor_center_top_bottom_task: Task<()>,
 1107    serialize_selections: Task<()>,
 1108    serialize_folds: Task<()>,
 1109    mouse_cursor_hidden: bool,
 1110    minimap: Option<Entity<Self>>,
 1111    hide_mouse_mode: HideMouseMode,
 1112    pub change_list: ChangeList,
 1113    inline_value_cache: InlineValueCache,
 1114    selection_drag_state: SelectionDragState,
 1115    drag_and_drop_selection_enabled: bool,
 1116}
 1117
 1118#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1119enum NextScrollCursorCenterTopBottom {
 1120    #[default]
 1121    Center,
 1122    Top,
 1123    Bottom,
 1124}
 1125
 1126impl NextScrollCursorCenterTopBottom {
 1127    fn next(&self) -> Self {
 1128        match self {
 1129            Self::Center => Self::Top,
 1130            Self::Top => Self::Bottom,
 1131            Self::Bottom => Self::Center,
 1132        }
 1133    }
 1134}
 1135
 1136#[derive(Clone)]
 1137pub struct EditorSnapshot {
 1138    pub mode: EditorMode,
 1139    show_gutter: bool,
 1140    show_line_numbers: Option<bool>,
 1141    show_git_diff_gutter: Option<bool>,
 1142    show_code_actions: Option<bool>,
 1143    show_runnables: Option<bool>,
 1144    show_breakpoints: Option<bool>,
 1145    git_blame_gutter_max_author_length: Option<usize>,
 1146    pub display_snapshot: DisplaySnapshot,
 1147    pub placeholder_text: Option<Arc<str>>,
 1148    is_focused: bool,
 1149    scroll_anchor: ScrollAnchor,
 1150    ongoing_scroll: OngoingScroll,
 1151    current_line_highlight: CurrentLineHighlight,
 1152    gutter_hovered: bool,
 1153}
 1154
 1155#[derive(Default, Debug, Clone, Copy)]
 1156pub struct GutterDimensions {
 1157    pub left_padding: Pixels,
 1158    pub right_padding: Pixels,
 1159    pub width: Pixels,
 1160    pub margin: Pixels,
 1161    pub git_blame_entries_width: Option<Pixels>,
 1162}
 1163
 1164impl GutterDimensions {
 1165    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1166        Self {
 1167            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1168            ..Default::default()
 1169        }
 1170    }
 1171
 1172    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1173        -cx.text_system().descent(font_id, font_size)
 1174    }
 1175    /// The full width of the space taken up by the gutter.
 1176    pub fn full_width(&self) -> Pixels {
 1177        self.margin + self.width
 1178    }
 1179
 1180    /// The width of the space reserved for the fold indicators,
 1181    /// use alongside 'justify_end' and `gutter_width` to
 1182    /// right align content with the line numbers
 1183    pub fn fold_area_width(&self) -> Pixels {
 1184        self.margin + self.right_padding
 1185    }
 1186}
 1187
 1188#[derive(Debug)]
 1189pub struct RemoteSelection {
 1190    pub replica_id: ReplicaId,
 1191    pub selection: Selection<Anchor>,
 1192    pub cursor_shape: CursorShape,
 1193    pub collaborator_id: CollaboratorId,
 1194    pub line_mode: bool,
 1195    pub user_name: Option<SharedString>,
 1196    pub color: PlayerColor,
 1197}
 1198
 1199#[derive(Clone, Debug)]
 1200struct SelectionHistoryEntry {
 1201    selections: Arc<[Selection<Anchor>]>,
 1202    select_next_state: Option<SelectNextState>,
 1203    select_prev_state: Option<SelectNextState>,
 1204    add_selections_state: Option<AddSelectionsState>,
 1205}
 1206
 1207#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1208enum SelectionHistoryMode {
 1209    Normal,
 1210    Undoing,
 1211    Redoing,
 1212    Skipping,
 1213}
 1214
 1215#[derive(Clone, PartialEq, Eq, Hash)]
 1216struct HoveredCursor {
 1217    replica_id: u16,
 1218    selection_id: usize,
 1219}
 1220
 1221impl Default for SelectionHistoryMode {
 1222    fn default() -> Self {
 1223        Self::Normal
 1224    }
 1225}
 1226
 1227#[derive(Debug)]
 1228pub struct SelectionEffects {
 1229    nav_history: bool,
 1230    completions: bool,
 1231    scroll: Option<Autoscroll>,
 1232}
 1233
 1234impl Default for SelectionEffects {
 1235    fn default() -> Self {
 1236        Self {
 1237            nav_history: true,
 1238            completions: true,
 1239            scroll: Some(Autoscroll::fit()),
 1240        }
 1241    }
 1242}
 1243impl SelectionEffects {
 1244    pub fn scroll(scroll: Autoscroll) -> Self {
 1245        Self {
 1246            scroll: Some(scroll),
 1247            ..Default::default()
 1248        }
 1249    }
 1250
 1251    pub fn no_scroll() -> Self {
 1252        Self {
 1253            scroll: None,
 1254            ..Default::default()
 1255        }
 1256    }
 1257
 1258    pub fn completions(self, completions: bool) -> Self {
 1259        Self {
 1260            completions,
 1261            ..self
 1262        }
 1263    }
 1264
 1265    pub fn nav_history(self, nav_history: bool) -> Self {
 1266        Self {
 1267            nav_history,
 1268            ..self
 1269        }
 1270    }
 1271}
 1272
 1273struct DeferredSelectionEffectsState {
 1274    changed: bool,
 1275    effects: SelectionEffects,
 1276    old_cursor_position: Anchor,
 1277    history_entry: SelectionHistoryEntry,
 1278}
 1279
 1280#[derive(Default)]
 1281struct SelectionHistory {
 1282    #[allow(clippy::type_complexity)]
 1283    selections_by_transaction:
 1284        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1285    mode: SelectionHistoryMode,
 1286    undo_stack: VecDeque<SelectionHistoryEntry>,
 1287    redo_stack: VecDeque<SelectionHistoryEntry>,
 1288}
 1289
 1290impl SelectionHistory {
 1291    #[track_caller]
 1292    fn insert_transaction(
 1293        &mut self,
 1294        transaction_id: TransactionId,
 1295        selections: Arc<[Selection<Anchor>]>,
 1296    ) {
 1297        if selections.is_empty() {
 1298            log::error!(
 1299                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1300                std::panic::Location::caller()
 1301            );
 1302            return;
 1303        }
 1304        self.selections_by_transaction
 1305            .insert(transaction_id, (selections, None));
 1306    }
 1307
 1308    #[allow(clippy::type_complexity)]
 1309    fn transaction(
 1310        &self,
 1311        transaction_id: TransactionId,
 1312    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1313        self.selections_by_transaction.get(&transaction_id)
 1314    }
 1315
 1316    #[allow(clippy::type_complexity)]
 1317    fn transaction_mut(
 1318        &mut self,
 1319        transaction_id: TransactionId,
 1320    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1321        self.selections_by_transaction.get_mut(&transaction_id)
 1322    }
 1323
 1324    fn push(&mut self, entry: SelectionHistoryEntry) {
 1325        if !entry.selections.is_empty() {
 1326            match self.mode {
 1327                SelectionHistoryMode::Normal => {
 1328                    self.push_undo(entry);
 1329                    self.redo_stack.clear();
 1330                }
 1331                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1332                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1333                SelectionHistoryMode::Skipping => {}
 1334            }
 1335        }
 1336    }
 1337
 1338    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1339        if self
 1340            .undo_stack
 1341            .back()
 1342            .map_or(true, |e| e.selections != entry.selections)
 1343        {
 1344            self.undo_stack.push_back(entry);
 1345            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1346                self.undo_stack.pop_front();
 1347            }
 1348        }
 1349    }
 1350
 1351    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1352        if self
 1353            .redo_stack
 1354            .back()
 1355            .map_or(true, |e| e.selections != entry.selections)
 1356        {
 1357            self.redo_stack.push_back(entry);
 1358            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1359                self.redo_stack.pop_front();
 1360            }
 1361        }
 1362    }
 1363}
 1364
 1365#[derive(Clone, Copy)]
 1366pub struct RowHighlightOptions {
 1367    pub autoscroll: bool,
 1368    pub include_gutter: bool,
 1369}
 1370
 1371impl Default for RowHighlightOptions {
 1372    fn default() -> Self {
 1373        Self {
 1374            autoscroll: Default::default(),
 1375            include_gutter: true,
 1376        }
 1377    }
 1378}
 1379
 1380struct RowHighlight {
 1381    index: usize,
 1382    range: Range<Anchor>,
 1383    color: Hsla,
 1384    options: RowHighlightOptions,
 1385    type_id: TypeId,
 1386}
 1387
 1388#[derive(Clone, Debug)]
 1389struct AddSelectionsState {
 1390    groups: Vec<AddSelectionsGroup>,
 1391}
 1392
 1393#[derive(Clone, Debug)]
 1394struct AddSelectionsGroup {
 1395    above: bool,
 1396    stack: Vec<usize>,
 1397}
 1398
 1399#[derive(Clone)]
 1400struct SelectNextState {
 1401    query: AhoCorasick,
 1402    wordwise: bool,
 1403    done: bool,
 1404}
 1405
 1406impl std::fmt::Debug for SelectNextState {
 1407    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1408        f.debug_struct(std::any::type_name::<Self>())
 1409            .field("wordwise", &self.wordwise)
 1410            .field("done", &self.done)
 1411            .finish()
 1412    }
 1413}
 1414
 1415#[derive(Debug)]
 1416struct AutocloseRegion {
 1417    selection_id: usize,
 1418    range: Range<Anchor>,
 1419    pair: BracketPair,
 1420}
 1421
 1422#[derive(Debug)]
 1423struct SnippetState {
 1424    ranges: Vec<Vec<Range<Anchor>>>,
 1425    active_index: usize,
 1426    choices: Vec<Option<Vec<String>>>,
 1427}
 1428
 1429#[doc(hidden)]
 1430pub struct RenameState {
 1431    pub range: Range<Anchor>,
 1432    pub old_name: Arc<str>,
 1433    pub editor: Entity<Editor>,
 1434    block_id: CustomBlockId,
 1435}
 1436
 1437struct InvalidationStack<T>(Vec<T>);
 1438
 1439struct RegisteredInlineCompletionProvider {
 1440    provider: Arc<dyn InlineCompletionProviderHandle>,
 1441    _subscription: Subscription,
 1442}
 1443
 1444#[derive(Debug, PartialEq, Eq)]
 1445pub struct ActiveDiagnosticGroup {
 1446    pub active_range: Range<Anchor>,
 1447    pub active_message: String,
 1448    pub group_id: usize,
 1449    pub blocks: HashSet<CustomBlockId>,
 1450}
 1451
 1452#[derive(Debug, PartialEq, Eq)]
 1453
 1454pub(crate) enum ActiveDiagnostic {
 1455    None,
 1456    All,
 1457    Group(ActiveDiagnosticGroup),
 1458}
 1459
 1460#[derive(Serialize, Deserialize, Clone, Debug)]
 1461pub struct ClipboardSelection {
 1462    /// The number of bytes in this selection.
 1463    pub len: usize,
 1464    /// Whether this was a full-line selection.
 1465    pub is_entire_line: bool,
 1466    /// The indentation of the first line when this content was originally copied.
 1467    pub first_line_indent: u32,
 1468}
 1469
 1470// selections, scroll behavior, was newest selection reversed
 1471type SelectSyntaxNodeHistoryState = (
 1472    Box<[Selection<usize>]>,
 1473    SelectSyntaxNodeScrollBehavior,
 1474    bool,
 1475);
 1476
 1477#[derive(Default)]
 1478struct SelectSyntaxNodeHistory {
 1479    stack: Vec<SelectSyntaxNodeHistoryState>,
 1480    // disable temporarily to allow changing selections without losing the stack
 1481    pub disable_clearing: bool,
 1482}
 1483
 1484impl SelectSyntaxNodeHistory {
 1485    pub fn try_clear(&mut self) {
 1486        if !self.disable_clearing {
 1487            self.stack.clear();
 1488        }
 1489    }
 1490
 1491    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1492        self.stack.push(selection);
 1493    }
 1494
 1495    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1496        self.stack.pop()
 1497    }
 1498}
 1499
 1500enum SelectSyntaxNodeScrollBehavior {
 1501    CursorTop,
 1502    FitSelection,
 1503    CursorBottom,
 1504}
 1505
 1506#[derive(Debug)]
 1507pub(crate) struct NavigationData {
 1508    cursor_anchor: Anchor,
 1509    cursor_position: Point,
 1510    scroll_anchor: ScrollAnchor,
 1511    scroll_top_row: u32,
 1512}
 1513
 1514#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1515pub enum GotoDefinitionKind {
 1516    Symbol,
 1517    Declaration,
 1518    Type,
 1519    Implementation,
 1520}
 1521
 1522#[derive(Debug, Clone)]
 1523enum InlayHintRefreshReason {
 1524    ModifiersChanged(bool),
 1525    Toggle(bool),
 1526    SettingsChange(InlayHintSettings),
 1527    NewLinesShown,
 1528    BufferEdited(HashSet<Arc<Language>>),
 1529    RefreshRequested,
 1530    ExcerptsRemoved(Vec<ExcerptId>),
 1531}
 1532
 1533impl InlayHintRefreshReason {
 1534    fn description(&self) -> &'static str {
 1535        match self {
 1536            Self::ModifiersChanged(_) => "modifiers changed",
 1537            Self::Toggle(_) => "toggle",
 1538            Self::SettingsChange(_) => "settings change",
 1539            Self::NewLinesShown => "new lines shown",
 1540            Self::BufferEdited(_) => "buffer edited",
 1541            Self::RefreshRequested => "refresh requested",
 1542            Self::ExcerptsRemoved(_) => "excerpts removed",
 1543        }
 1544    }
 1545}
 1546
 1547pub enum FormatTarget {
 1548    Buffers(HashSet<Entity<Buffer>>),
 1549    Ranges(Vec<Range<MultiBufferPoint>>),
 1550}
 1551
 1552pub(crate) struct FocusedBlock {
 1553    id: BlockId,
 1554    focus_handle: WeakFocusHandle,
 1555}
 1556
 1557#[derive(Clone)]
 1558enum JumpData {
 1559    MultiBufferRow {
 1560        row: MultiBufferRow,
 1561        line_offset_from_top: u32,
 1562    },
 1563    MultiBufferPoint {
 1564        excerpt_id: ExcerptId,
 1565        position: Point,
 1566        anchor: text::Anchor,
 1567        line_offset_from_top: u32,
 1568    },
 1569}
 1570
 1571pub enum MultibufferSelectionMode {
 1572    First,
 1573    All,
 1574}
 1575
 1576#[derive(Clone, Copy, Debug, Default)]
 1577pub struct RewrapOptions {
 1578    pub override_language_settings: bool,
 1579    pub preserve_existing_whitespace: bool,
 1580}
 1581
 1582impl Editor {
 1583    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1584        let buffer = cx.new(|cx| Buffer::local("", cx));
 1585        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1586        Self::new(
 1587            EditorMode::SingleLine { auto_width: false },
 1588            buffer,
 1589            None,
 1590            window,
 1591            cx,
 1592        )
 1593    }
 1594
 1595    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1596        let buffer = cx.new(|cx| Buffer::local("", cx));
 1597        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1598        Self::new(EditorMode::full(), buffer, None, window, cx)
 1599    }
 1600
 1601    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1602        let buffer = cx.new(|cx| Buffer::local("", cx));
 1603        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1604        Self::new(
 1605            EditorMode::SingleLine { auto_width: true },
 1606            buffer,
 1607            None,
 1608            window,
 1609            cx,
 1610        )
 1611    }
 1612
 1613    pub fn auto_height(
 1614        min_lines: usize,
 1615        max_lines: usize,
 1616        window: &mut Window,
 1617        cx: &mut Context<Self>,
 1618    ) -> Self {
 1619        let buffer = cx.new(|cx| Buffer::local("", cx));
 1620        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1621        Self::new(
 1622            EditorMode::AutoHeight {
 1623                min_lines,
 1624                max_lines,
 1625            },
 1626            buffer,
 1627            None,
 1628            window,
 1629            cx,
 1630        )
 1631    }
 1632
 1633    pub fn for_buffer(
 1634        buffer: Entity<Buffer>,
 1635        project: Option<Entity<Project>>,
 1636        window: &mut Window,
 1637        cx: &mut Context<Self>,
 1638    ) -> Self {
 1639        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1640        Self::new(EditorMode::full(), buffer, project, window, cx)
 1641    }
 1642
 1643    pub fn for_multibuffer(
 1644        buffer: Entity<MultiBuffer>,
 1645        project: Option<Entity<Project>>,
 1646        window: &mut Window,
 1647        cx: &mut Context<Self>,
 1648    ) -> Self {
 1649        Self::new(EditorMode::full(), buffer, project, window, cx)
 1650    }
 1651
 1652    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1653        let mut clone = Self::new(
 1654            self.mode.clone(),
 1655            self.buffer.clone(),
 1656            self.project.clone(),
 1657            window,
 1658            cx,
 1659        );
 1660        self.display_map.update(cx, |display_map, cx| {
 1661            let snapshot = display_map.snapshot(cx);
 1662            clone.display_map.update(cx, |display_map, cx| {
 1663                display_map.set_state(&snapshot, cx);
 1664            });
 1665        });
 1666        clone.folds_did_change(cx);
 1667        clone.selections.clone_state(&self.selections);
 1668        clone.scroll_manager.clone_state(&self.scroll_manager);
 1669        clone.searchable = self.searchable;
 1670        clone.read_only = self.read_only;
 1671        clone
 1672    }
 1673
 1674    pub fn new(
 1675        mode: EditorMode,
 1676        buffer: Entity<MultiBuffer>,
 1677        project: Option<Entity<Project>>,
 1678        window: &mut Window,
 1679        cx: &mut Context<Self>,
 1680    ) -> Self {
 1681        Editor::new_internal(mode, buffer, project, None, window, cx)
 1682    }
 1683
 1684    fn new_internal(
 1685        mode: EditorMode,
 1686        buffer: Entity<MultiBuffer>,
 1687        project: Option<Entity<Project>>,
 1688        display_map: Option<Entity<DisplayMap>>,
 1689        window: &mut Window,
 1690        cx: &mut Context<Self>,
 1691    ) -> Self {
 1692        debug_assert!(
 1693            display_map.is_none() || mode.is_minimap(),
 1694            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1695        );
 1696
 1697        let full_mode = mode.is_full();
 1698        let diagnostics_max_severity = if full_mode {
 1699            EditorSettings::get_global(cx)
 1700                .diagnostics_max_severity
 1701                .unwrap_or(DiagnosticSeverity::Hint)
 1702        } else {
 1703            DiagnosticSeverity::Off
 1704        };
 1705        let style = window.text_style();
 1706        let font_size = style.font_size.to_pixels(window.rem_size());
 1707        let editor = cx.entity().downgrade();
 1708        let fold_placeholder = FoldPlaceholder {
 1709            constrain_width: true,
 1710            render: Arc::new(move |fold_id, fold_range, cx| {
 1711                let editor = editor.clone();
 1712                div()
 1713                    .id(fold_id)
 1714                    .bg(cx.theme().colors().ghost_element_background)
 1715                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1716                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1717                    .rounded_xs()
 1718                    .size_full()
 1719                    .cursor_pointer()
 1720                    .child("")
 1721                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1722                    .on_click(move |_, _window, cx| {
 1723                        editor
 1724                            .update(cx, |editor, cx| {
 1725                                editor.unfold_ranges(
 1726                                    &[fold_range.start..fold_range.end],
 1727                                    true,
 1728                                    false,
 1729                                    cx,
 1730                                );
 1731                                cx.stop_propagation();
 1732                            })
 1733                            .ok();
 1734                    })
 1735                    .into_any()
 1736            }),
 1737            merge_adjacent: true,
 1738            ..FoldPlaceholder::default()
 1739        };
 1740        let display_map = display_map.unwrap_or_else(|| {
 1741            cx.new(|cx| {
 1742                DisplayMap::new(
 1743                    buffer.clone(),
 1744                    style.font(),
 1745                    font_size,
 1746                    None,
 1747                    FILE_HEADER_HEIGHT,
 1748                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1749                    fold_placeholder,
 1750                    diagnostics_max_severity,
 1751                    cx,
 1752                )
 1753            })
 1754        });
 1755
 1756        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1757
 1758        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1759
 1760        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1761            .then(|| language_settings::SoftWrap::None);
 1762
 1763        let mut project_subscriptions = Vec::new();
 1764        if mode.is_full() {
 1765            if let Some(project) = project.as_ref() {
 1766                project_subscriptions.push(cx.subscribe_in(
 1767                    project,
 1768                    window,
 1769                    |editor, _, event, window, cx| match event {
 1770                        project::Event::RefreshCodeLens => {
 1771                            // we always query lens with actions, without storing them, always refreshing them
 1772                        }
 1773                        project::Event::RefreshInlayHints => {
 1774                            editor
 1775                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1776                        }
 1777                        project::Event::LanguageServerAdded(..)
 1778                        | project::Event::LanguageServerRemoved(..) => {
 1779                            if editor.tasks_update_task.is_none() {
 1780                                editor.tasks_update_task =
 1781                                    Some(editor.refresh_runnables(window, cx));
 1782                            }
 1783                            editor.pull_diagnostics(None, window, cx);
 1784                        }
 1785                        project::Event::SnippetEdit(id, snippet_edits) => {
 1786                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1787                                let focus_handle = editor.focus_handle(cx);
 1788                                if focus_handle.is_focused(window) {
 1789                                    let snapshot = buffer.read(cx).snapshot();
 1790                                    for (range, snippet) in snippet_edits {
 1791                                        let editor_range =
 1792                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1793                                        editor
 1794                                            .insert_snippet(
 1795                                                &[editor_range],
 1796                                                snippet.clone(),
 1797                                                window,
 1798                                                cx,
 1799                                            )
 1800                                            .ok();
 1801                                    }
 1802                                }
 1803                            }
 1804                        }
 1805                        _ => {}
 1806                    },
 1807                ));
 1808                if let Some(task_inventory) = project
 1809                    .read(cx)
 1810                    .task_store()
 1811                    .read(cx)
 1812                    .task_inventory()
 1813                    .cloned()
 1814                {
 1815                    project_subscriptions.push(cx.observe_in(
 1816                        &task_inventory,
 1817                        window,
 1818                        |editor, _, window, cx| {
 1819                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1820                        },
 1821                    ));
 1822                };
 1823
 1824                project_subscriptions.push(cx.subscribe_in(
 1825                    &project.read(cx).breakpoint_store(),
 1826                    window,
 1827                    |editor, _, event, window, cx| match event {
 1828                        BreakpointStoreEvent::ClearDebugLines => {
 1829                            editor.clear_row_highlights::<ActiveDebugLine>();
 1830                            editor.refresh_inline_values(cx);
 1831                        }
 1832                        BreakpointStoreEvent::SetDebugLine => {
 1833                            if editor.go_to_active_debug_line(window, cx) {
 1834                                cx.stop_propagation();
 1835                            }
 1836
 1837                            editor.refresh_inline_values(cx);
 1838                        }
 1839                        _ => {}
 1840                    },
 1841                ));
 1842            }
 1843        }
 1844
 1845        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1846
 1847        let inlay_hint_settings =
 1848            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1849        let focus_handle = cx.focus_handle();
 1850        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1851            .detach();
 1852        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1853            .detach();
 1854        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1855            .detach();
 1856        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1857            .detach();
 1858        cx.observe_pending_input(window, Self::observe_pending_input)
 1859            .detach();
 1860
 1861        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1862            Some(false)
 1863        } else {
 1864            None
 1865        };
 1866
 1867        let breakpoint_store = match (&mode, project.as_ref()) {
 1868            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1869            _ => None,
 1870        };
 1871
 1872        let mut code_action_providers = Vec::new();
 1873        let mut load_uncommitted_diff = None;
 1874        if let Some(project) = project.clone() {
 1875            load_uncommitted_diff = Some(
 1876                update_uncommitted_diff_for_buffer(
 1877                    cx.entity(),
 1878                    &project,
 1879                    buffer.read(cx).all_buffers(),
 1880                    buffer.clone(),
 1881                    cx,
 1882                )
 1883                .shared(),
 1884            );
 1885            code_action_providers.push(Rc::new(project) as Rc<_>);
 1886        }
 1887
 1888        let mut editor = Self {
 1889            focus_handle,
 1890            show_cursor_when_unfocused: false,
 1891            last_focused_descendant: None,
 1892            buffer: buffer.clone(),
 1893            display_map: display_map.clone(),
 1894            selections,
 1895            scroll_manager: ScrollManager::new(cx),
 1896            columnar_selection_tail: None,
 1897            columnar_display_point: None,
 1898            add_selections_state: None,
 1899            select_next_state: None,
 1900            select_prev_state: None,
 1901            selection_history: SelectionHistory::default(),
 1902            defer_selection_effects: false,
 1903            deferred_selection_effects_state: None,
 1904            autoclose_regions: Vec::new(),
 1905            snippet_stack: InvalidationStack::default(),
 1906            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1907            ime_transaction: None,
 1908            active_diagnostics: ActiveDiagnostic::None,
 1909            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1910            inline_diagnostics_update: Task::ready(()),
 1911            inline_diagnostics: Vec::new(),
 1912            soft_wrap_mode_override,
 1913            diagnostics_max_severity,
 1914            hard_wrap: None,
 1915            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1916            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1917            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1918            project,
 1919            blink_manager: blink_manager.clone(),
 1920            show_local_selections: true,
 1921            show_scrollbars: ScrollbarAxes {
 1922                horizontal: full_mode,
 1923                vertical: full_mode,
 1924            },
 1925            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1926            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1927            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1928            show_gutter: mode.is_full(),
 1929            show_line_numbers: None,
 1930            use_relative_line_numbers: None,
 1931            disable_expand_excerpt_buttons: false,
 1932            show_git_diff_gutter: None,
 1933            show_code_actions: None,
 1934            show_runnables: None,
 1935            show_breakpoints: None,
 1936            show_wrap_guides: None,
 1937            show_indent_guides,
 1938            placeholder_text: None,
 1939            highlight_order: 0,
 1940            highlighted_rows: HashMap::default(),
 1941            background_highlights: TreeMap::default(),
 1942            gutter_highlights: TreeMap::default(),
 1943            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1944            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1945            nav_history: None,
 1946            context_menu: RefCell::new(None),
 1947            context_menu_options: None,
 1948            mouse_context_menu: None,
 1949            completion_tasks: Vec::new(),
 1950            inline_blame_popover: None,
 1951            inline_blame_popover_show_task: None,
 1952            signature_help_state: SignatureHelpState::default(),
 1953            auto_signature_help: None,
 1954            find_all_references_task_sources: Vec::new(),
 1955            next_completion_id: 0,
 1956            next_inlay_id: 0,
 1957            code_action_providers,
 1958            available_code_actions: None,
 1959            code_actions_task: None,
 1960            quick_selection_highlight_task: None,
 1961            debounced_selection_highlight_task: None,
 1962            document_highlights_task: None,
 1963            linked_editing_range_task: None,
 1964            pending_rename: None,
 1965            searchable: true,
 1966            cursor_shape: EditorSettings::get_global(cx)
 1967                .cursor_shape
 1968                .unwrap_or_default(),
 1969            current_line_highlight: None,
 1970            autoindent_mode: Some(AutoindentMode::EachLine),
 1971            collapse_matches: false,
 1972            workspace: None,
 1973            input_enabled: true,
 1974            use_modal_editing: mode.is_full(),
 1975            read_only: mode.is_minimap(),
 1976            use_autoclose: true,
 1977            use_auto_surround: true,
 1978            auto_replace_emoji_shortcode: false,
 1979            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1980            leader_id: None,
 1981            remote_id: None,
 1982            hover_state: HoverState::default(),
 1983            pending_mouse_down: None,
 1984            hovered_link_state: None,
 1985            edit_prediction_provider: None,
 1986            active_inline_completion: None,
 1987            stale_inline_completion_in_menu: None,
 1988            edit_prediction_preview: EditPredictionPreview::Inactive {
 1989                released_too_fast: false,
 1990            },
 1991            inline_diagnostics_enabled: mode.is_full(),
 1992            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1993            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1994
 1995            gutter_hovered: false,
 1996            pixel_position_of_newest_cursor: None,
 1997            last_bounds: None,
 1998            last_position_map: None,
 1999            expect_bounds_change: None,
 2000            gutter_dimensions: GutterDimensions::default(),
 2001            style: None,
 2002            show_cursor_names: false,
 2003            hovered_cursors: HashMap::default(),
 2004            next_editor_action_id: EditorActionId::default(),
 2005            editor_actions: Rc::default(),
 2006            inline_completions_hidden_for_vim_mode: false,
 2007            show_inline_completions_override: None,
 2008            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2009            edit_prediction_settings: EditPredictionSettings::Disabled,
 2010            edit_prediction_indent_conflict: false,
 2011            edit_prediction_requires_modifier_in_indent_conflict: true,
 2012            custom_context_menu: None,
 2013            show_git_blame_gutter: false,
 2014            show_git_blame_inline: false,
 2015            show_selection_menu: None,
 2016            show_git_blame_inline_delay_task: None,
 2017            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2018            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2019            serialize_dirty_buffers: !mode.is_minimap()
 2020                && ProjectSettings::get_global(cx)
 2021                    .session
 2022                    .restore_unsaved_buffers,
 2023            blame: None,
 2024            blame_subscription: None,
 2025            tasks: BTreeMap::default(),
 2026
 2027            breakpoint_store,
 2028            gutter_breakpoint_indicator: (None, None),
 2029            hovered_diff_hunk_row: None,
 2030            _subscriptions: vec![
 2031                cx.observe(&buffer, Self::on_buffer_changed),
 2032                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2033                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2034                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2035                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2036                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2037                cx.observe_window_activation(window, |editor, window, cx| {
 2038                    let active = window.is_window_active();
 2039                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2040                        if active {
 2041                            blink_manager.enable(cx);
 2042                        } else {
 2043                            blink_manager.disable(cx);
 2044                        }
 2045                    });
 2046                    if active {
 2047                        editor.show_mouse_cursor();
 2048                    }
 2049                }),
 2050            ],
 2051            tasks_update_task: None,
 2052            pull_diagnostics_task: Task::ready(()),
 2053            linked_edit_ranges: Default::default(),
 2054            in_project_search: false,
 2055            previous_search_ranges: None,
 2056            breadcrumb_header: None,
 2057            focused_block: None,
 2058            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2059            addons: HashMap::default(),
 2060            registered_buffers: HashMap::default(),
 2061            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2062            selection_mark_mode: false,
 2063            toggle_fold_multiple_buffers: Task::ready(()),
 2064            serialize_selections: Task::ready(()),
 2065            serialize_folds: Task::ready(()),
 2066            text_style_refinement: None,
 2067            load_diff_task: load_uncommitted_diff,
 2068            temporary_diff_override: false,
 2069            mouse_cursor_hidden: false,
 2070            minimap: None,
 2071            hide_mouse_mode: EditorSettings::get_global(cx)
 2072                .hide_mouse
 2073                .unwrap_or_default(),
 2074            change_list: ChangeList::new(),
 2075            mode,
 2076            selection_drag_state: SelectionDragState::None,
 2077            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2078        };
 2079        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2080            editor
 2081                ._subscriptions
 2082                .push(cx.observe(breakpoints, |_, _, cx| {
 2083                    cx.notify();
 2084                }));
 2085        }
 2086        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2087        editor._subscriptions.extend(project_subscriptions);
 2088
 2089        editor._subscriptions.push(cx.subscribe_in(
 2090            &cx.entity(),
 2091            window,
 2092            |editor, _, e: &EditorEvent, window, cx| match e {
 2093                EditorEvent::ScrollPositionChanged { local, .. } => {
 2094                    if *local {
 2095                        let new_anchor = editor.scroll_manager.anchor();
 2096                        let snapshot = editor.snapshot(window, cx);
 2097                        editor.update_restoration_data(cx, move |data| {
 2098                            data.scroll_position = (
 2099                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2100                                new_anchor.offset,
 2101                            );
 2102                        });
 2103                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2104                        editor.inline_blame_popover.take();
 2105                    }
 2106                }
 2107                EditorEvent::Edited { .. } => {
 2108                    if !vim_enabled(cx) {
 2109                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2110                        let pop_state = editor
 2111                            .change_list
 2112                            .last()
 2113                            .map(|previous| {
 2114                                previous.len() == selections.len()
 2115                                    && previous.iter().enumerate().all(|(ix, p)| {
 2116                                        p.to_display_point(&map).row()
 2117                                            == selections[ix].head().row()
 2118                                    })
 2119                            })
 2120                            .unwrap_or(false);
 2121                        let new_positions = selections
 2122                            .into_iter()
 2123                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2124                            .collect();
 2125                        editor
 2126                            .change_list
 2127                            .push_to_change_list(pop_state, new_positions);
 2128                    }
 2129                }
 2130                _ => (),
 2131            },
 2132        ));
 2133
 2134        if let Some(dap_store) = editor
 2135            .project
 2136            .as_ref()
 2137            .map(|project| project.read(cx).dap_store())
 2138        {
 2139            let weak_editor = cx.weak_entity();
 2140
 2141            editor
 2142                ._subscriptions
 2143                .push(
 2144                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2145                        let session_entity = cx.entity();
 2146                        weak_editor
 2147                            .update(cx, |editor, cx| {
 2148                                editor._subscriptions.push(
 2149                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2150                                );
 2151                            })
 2152                            .ok();
 2153                    }),
 2154                );
 2155
 2156            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2157                editor
 2158                    ._subscriptions
 2159                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2160            }
 2161        }
 2162
 2163        // skip adding the initial selection to selection history
 2164        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2165        editor.end_selection(window, cx);
 2166        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2167
 2168        editor.scroll_manager.show_scrollbars(window, cx);
 2169        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2170
 2171        if full_mode {
 2172            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2173            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2174
 2175            if editor.git_blame_inline_enabled {
 2176                editor.start_git_blame_inline(false, window, cx);
 2177            }
 2178
 2179            editor.go_to_active_debug_line(window, cx);
 2180
 2181            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2182                if let Some(project) = editor.project.as_ref() {
 2183                    let handle = project.update(cx, |project, cx| {
 2184                        project.register_buffer_with_language_servers(&buffer, cx)
 2185                    });
 2186                    editor
 2187                        .registered_buffers
 2188                        .insert(buffer.read(cx).remote_id(), handle);
 2189                }
 2190            }
 2191
 2192            editor.minimap =
 2193                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2194            editor.pull_diagnostics(None, window, cx);
 2195        }
 2196
 2197        editor.report_editor_event("Editor Opened", None, cx);
 2198        editor
 2199    }
 2200
 2201    pub fn deploy_mouse_context_menu(
 2202        &mut self,
 2203        position: gpui::Point<Pixels>,
 2204        context_menu: Entity<ContextMenu>,
 2205        window: &mut Window,
 2206        cx: &mut Context<Self>,
 2207    ) {
 2208        self.mouse_context_menu = Some(MouseContextMenu::new(
 2209            self,
 2210            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2211            context_menu,
 2212            window,
 2213            cx,
 2214        ));
 2215    }
 2216
 2217    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2218        self.mouse_context_menu
 2219            .as_ref()
 2220            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2221    }
 2222
 2223    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2224        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2225    }
 2226
 2227    fn key_context_internal(
 2228        &self,
 2229        has_active_edit_prediction: bool,
 2230        window: &Window,
 2231        cx: &App,
 2232    ) -> KeyContext {
 2233        let mut key_context = KeyContext::new_with_defaults();
 2234        key_context.add("Editor");
 2235        let mode = match self.mode {
 2236            EditorMode::SingleLine { .. } => "single_line",
 2237            EditorMode::AutoHeight { .. } => "auto_height",
 2238            EditorMode::Minimap { .. } => "minimap",
 2239            EditorMode::Full { .. } => "full",
 2240        };
 2241
 2242        if EditorSettings::jupyter_enabled(cx) {
 2243            key_context.add("jupyter");
 2244        }
 2245
 2246        key_context.set("mode", mode);
 2247        if self.pending_rename.is_some() {
 2248            key_context.add("renaming");
 2249        }
 2250
 2251        match self.context_menu.borrow().as_ref() {
 2252            Some(CodeContextMenu::Completions(_)) => {
 2253                key_context.add("menu");
 2254                key_context.add("showing_completions");
 2255            }
 2256            Some(CodeContextMenu::CodeActions(_)) => {
 2257                key_context.add("menu");
 2258                key_context.add("showing_code_actions")
 2259            }
 2260            None => {}
 2261        }
 2262
 2263        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2264        if !self.focus_handle(cx).contains_focused(window, cx)
 2265            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2266        {
 2267            for addon in self.addons.values() {
 2268                addon.extend_key_context(&mut key_context, cx)
 2269            }
 2270        }
 2271
 2272        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2273            if let Some(extension) = singleton_buffer
 2274                .read(cx)
 2275                .file()
 2276                .and_then(|file| file.path().extension()?.to_str())
 2277            {
 2278                key_context.set("extension", extension.to_string());
 2279            }
 2280        } else {
 2281            key_context.add("multibuffer");
 2282        }
 2283
 2284        if has_active_edit_prediction {
 2285            if self.edit_prediction_in_conflict() {
 2286                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2287            } else {
 2288                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2289                key_context.add("copilot_suggestion");
 2290            }
 2291        }
 2292
 2293        if self.selection_mark_mode {
 2294            key_context.add("selection_mode");
 2295        }
 2296
 2297        key_context
 2298    }
 2299
 2300    fn show_mouse_cursor(&mut self) {
 2301        self.mouse_cursor_hidden = false;
 2302    }
 2303
 2304    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2305        self.mouse_cursor_hidden = match origin {
 2306            HideMouseCursorOrigin::TypingAction => {
 2307                matches!(
 2308                    self.hide_mouse_mode,
 2309                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2310                )
 2311            }
 2312            HideMouseCursorOrigin::MovementAction => {
 2313                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2314            }
 2315        };
 2316    }
 2317
 2318    pub fn edit_prediction_in_conflict(&self) -> bool {
 2319        if !self.show_edit_predictions_in_menu() {
 2320            return false;
 2321        }
 2322
 2323        let showing_completions = self
 2324            .context_menu
 2325            .borrow()
 2326            .as_ref()
 2327            .map_or(false, |context| {
 2328                matches!(context, CodeContextMenu::Completions(_))
 2329            });
 2330
 2331        showing_completions
 2332            || self.edit_prediction_requires_modifier()
 2333            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2334            // bindings to insert tab characters.
 2335            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2336    }
 2337
 2338    pub fn accept_edit_prediction_keybind(
 2339        &self,
 2340        accept_partial: bool,
 2341        window: &Window,
 2342        cx: &App,
 2343    ) -> AcceptEditPredictionBinding {
 2344        let key_context = self.key_context_internal(true, window, cx);
 2345        let in_conflict = self.edit_prediction_in_conflict();
 2346
 2347        let bindings = if accept_partial {
 2348            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2349        } else {
 2350            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2351        };
 2352
 2353        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2354        // just the first one.
 2355        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2356            !in_conflict
 2357                || binding
 2358                    .keystrokes()
 2359                    .first()
 2360                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2361        }))
 2362    }
 2363
 2364    pub fn new_file(
 2365        workspace: &mut Workspace,
 2366        _: &workspace::NewFile,
 2367        window: &mut Window,
 2368        cx: &mut Context<Workspace>,
 2369    ) {
 2370        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2371            "Failed to create buffer",
 2372            window,
 2373            cx,
 2374            |e, _, _| match e.error_code() {
 2375                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2376                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2377                e.error_tag("required").unwrap_or("the latest version")
 2378            )),
 2379                _ => None,
 2380            },
 2381        );
 2382    }
 2383
 2384    pub fn new_in_workspace(
 2385        workspace: &mut Workspace,
 2386        window: &mut Window,
 2387        cx: &mut Context<Workspace>,
 2388    ) -> Task<Result<Entity<Editor>>> {
 2389        let project = workspace.project().clone();
 2390        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2391
 2392        cx.spawn_in(window, async move |workspace, cx| {
 2393            let buffer = create.await?;
 2394            workspace.update_in(cx, |workspace, window, cx| {
 2395                let editor =
 2396                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2397                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2398                editor
 2399            })
 2400        })
 2401    }
 2402
 2403    fn new_file_vertical(
 2404        workspace: &mut Workspace,
 2405        _: &workspace::NewFileSplitVertical,
 2406        window: &mut Window,
 2407        cx: &mut Context<Workspace>,
 2408    ) {
 2409        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2410    }
 2411
 2412    fn new_file_horizontal(
 2413        workspace: &mut Workspace,
 2414        _: &workspace::NewFileSplitHorizontal,
 2415        window: &mut Window,
 2416        cx: &mut Context<Workspace>,
 2417    ) {
 2418        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2419    }
 2420
 2421    fn new_file_in_direction(
 2422        workspace: &mut Workspace,
 2423        direction: SplitDirection,
 2424        window: &mut Window,
 2425        cx: &mut Context<Workspace>,
 2426    ) {
 2427        let project = workspace.project().clone();
 2428        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2429
 2430        cx.spawn_in(window, async move |workspace, cx| {
 2431            let buffer = create.await?;
 2432            workspace.update_in(cx, move |workspace, window, cx| {
 2433                workspace.split_item(
 2434                    direction,
 2435                    Box::new(
 2436                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2437                    ),
 2438                    window,
 2439                    cx,
 2440                )
 2441            })?;
 2442            anyhow::Ok(())
 2443        })
 2444        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2445            match e.error_code() {
 2446                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2447                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2448                e.error_tag("required").unwrap_or("the latest version")
 2449            )),
 2450                _ => None,
 2451            }
 2452        });
 2453    }
 2454
 2455    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2456        self.leader_id
 2457    }
 2458
 2459    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2460        &self.buffer
 2461    }
 2462
 2463    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2464        self.workspace.as_ref()?.0.upgrade()
 2465    }
 2466
 2467    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2468        self.buffer().read(cx).title(cx)
 2469    }
 2470
 2471    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2472        let git_blame_gutter_max_author_length = self
 2473            .render_git_blame_gutter(cx)
 2474            .then(|| {
 2475                if let Some(blame) = self.blame.as_ref() {
 2476                    let max_author_length =
 2477                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2478                    Some(max_author_length)
 2479                } else {
 2480                    None
 2481                }
 2482            })
 2483            .flatten();
 2484
 2485        EditorSnapshot {
 2486            mode: self.mode.clone(),
 2487            show_gutter: self.show_gutter,
 2488            show_line_numbers: self.show_line_numbers,
 2489            show_git_diff_gutter: self.show_git_diff_gutter,
 2490            show_code_actions: self.show_code_actions,
 2491            show_runnables: self.show_runnables,
 2492            show_breakpoints: self.show_breakpoints,
 2493            git_blame_gutter_max_author_length,
 2494            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2495            scroll_anchor: self.scroll_manager.anchor(),
 2496            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2497            placeholder_text: self.placeholder_text.clone(),
 2498            is_focused: self.focus_handle.is_focused(window),
 2499            current_line_highlight: self
 2500                .current_line_highlight
 2501                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2502            gutter_hovered: self.gutter_hovered,
 2503        }
 2504    }
 2505
 2506    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2507        self.buffer.read(cx).language_at(point, cx)
 2508    }
 2509
 2510    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2511        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2512    }
 2513
 2514    pub fn active_excerpt(
 2515        &self,
 2516        cx: &App,
 2517    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2518        self.buffer
 2519            .read(cx)
 2520            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2521    }
 2522
 2523    pub fn mode(&self) -> &EditorMode {
 2524        &self.mode
 2525    }
 2526
 2527    pub fn set_mode(&mut self, mode: EditorMode) {
 2528        self.mode = mode;
 2529    }
 2530
 2531    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2532        self.collaboration_hub.as_deref()
 2533    }
 2534
 2535    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2536        self.collaboration_hub = Some(hub);
 2537    }
 2538
 2539    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2540        self.in_project_search = in_project_search;
 2541    }
 2542
 2543    pub fn set_custom_context_menu(
 2544        &mut self,
 2545        f: impl 'static
 2546        + Fn(
 2547            &mut Self,
 2548            DisplayPoint,
 2549            &mut Window,
 2550            &mut Context<Self>,
 2551        ) -> Option<Entity<ui::ContextMenu>>,
 2552    ) {
 2553        self.custom_context_menu = Some(Box::new(f))
 2554    }
 2555
 2556    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2557        self.completion_provider = provider;
 2558    }
 2559
 2560    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2561        self.semantics_provider.clone()
 2562    }
 2563
 2564    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2565        self.semantics_provider = provider;
 2566    }
 2567
 2568    pub fn set_edit_prediction_provider<T>(
 2569        &mut self,
 2570        provider: Option<Entity<T>>,
 2571        window: &mut Window,
 2572        cx: &mut Context<Self>,
 2573    ) where
 2574        T: EditPredictionProvider,
 2575    {
 2576        self.edit_prediction_provider =
 2577            provider.map(|provider| RegisteredInlineCompletionProvider {
 2578                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2579                    if this.focus_handle.is_focused(window) {
 2580                        this.update_visible_inline_completion(window, cx);
 2581                    }
 2582                }),
 2583                provider: Arc::new(provider),
 2584            });
 2585        self.update_edit_prediction_settings(cx);
 2586        self.refresh_inline_completion(false, false, window, cx);
 2587    }
 2588
 2589    pub fn placeholder_text(&self) -> Option<&str> {
 2590        self.placeholder_text.as_deref()
 2591    }
 2592
 2593    pub fn set_placeholder_text(
 2594        &mut self,
 2595        placeholder_text: impl Into<Arc<str>>,
 2596        cx: &mut Context<Self>,
 2597    ) {
 2598        let placeholder_text = Some(placeholder_text.into());
 2599        if self.placeholder_text != placeholder_text {
 2600            self.placeholder_text = placeholder_text;
 2601            cx.notify();
 2602        }
 2603    }
 2604
 2605    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2606        self.cursor_shape = cursor_shape;
 2607
 2608        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2609        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2610
 2611        cx.notify();
 2612    }
 2613
 2614    pub fn set_current_line_highlight(
 2615        &mut self,
 2616        current_line_highlight: Option<CurrentLineHighlight>,
 2617    ) {
 2618        self.current_line_highlight = current_line_highlight;
 2619    }
 2620
 2621    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2622        self.collapse_matches = collapse_matches;
 2623    }
 2624
 2625    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2626        let buffers = self.buffer.read(cx).all_buffers();
 2627        let Some(project) = self.project.as_ref() else {
 2628            return;
 2629        };
 2630        project.update(cx, |project, cx| {
 2631            for buffer in buffers {
 2632                self.registered_buffers
 2633                    .entry(buffer.read(cx).remote_id())
 2634                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2635            }
 2636        })
 2637    }
 2638
 2639    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2640        if self.collapse_matches {
 2641            return range.start..range.start;
 2642        }
 2643        range.clone()
 2644    }
 2645
 2646    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2647        if self.display_map.read(cx).clip_at_line_ends != clip {
 2648            self.display_map
 2649                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2650        }
 2651    }
 2652
 2653    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2654        self.input_enabled = input_enabled;
 2655    }
 2656
 2657    pub fn set_inline_completions_hidden_for_vim_mode(
 2658        &mut self,
 2659        hidden: bool,
 2660        window: &mut Window,
 2661        cx: &mut Context<Self>,
 2662    ) {
 2663        if hidden != self.inline_completions_hidden_for_vim_mode {
 2664            self.inline_completions_hidden_for_vim_mode = hidden;
 2665            if hidden {
 2666                self.update_visible_inline_completion(window, cx);
 2667            } else {
 2668                self.refresh_inline_completion(true, false, window, cx);
 2669            }
 2670        }
 2671    }
 2672
 2673    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2674        self.menu_inline_completions_policy = value;
 2675    }
 2676
 2677    pub fn set_autoindent(&mut self, autoindent: bool) {
 2678        if autoindent {
 2679            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2680        } else {
 2681            self.autoindent_mode = None;
 2682        }
 2683    }
 2684
 2685    pub fn read_only(&self, cx: &App) -> bool {
 2686        self.read_only || self.buffer.read(cx).read_only()
 2687    }
 2688
 2689    pub fn set_read_only(&mut self, read_only: bool) {
 2690        self.read_only = read_only;
 2691    }
 2692
 2693    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2694        self.use_autoclose = autoclose;
 2695    }
 2696
 2697    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2698        self.use_auto_surround = auto_surround;
 2699    }
 2700
 2701    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2702        self.auto_replace_emoji_shortcode = auto_replace;
 2703    }
 2704
 2705    pub fn toggle_edit_predictions(
 2706        &mut self,
 2707        _: &ToggleEditPrediction,
 2708        window: &mut Window,
 2709        cx: &mut Context<Self>,
 2710    ) {
 2711        if self.show_inline_completions_override.is_some() {
 2712            self.set_show_edit_predictions(None, window, cx);
 2713        } else {
 2714            let show_edit_predictions = !self.edit_predictions_enabled();
 2715            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2716        }
 2717    }
 2718
 2719    pub fn set_show_edit_predictions(
 2720        &mut self,
 2721        show_edit_predictions: Option<bool>,
 2722        window: &mut Window,
 2723        cx: &mut Context<Self>,
 2724    ) {
 2725        self.show_inline_completions_override = show_edit_predictions;
 2726        self.update_edit_prediction_settings(cx);
 2727
 2728        if let Some(false) = show_edit_predictions {
 2729            self.discard_inline_completion(false, cx);
 2730        } else {
 2731            self.refresh_inline_completion(false, true, window, cx);
 2732        }
 2733    }
 2734
 2735    fn inline_completions_disabled_in_scope(
 2736        &self,
 2737        buffer: &Entity<Buffer>,
 2738        buffer_position: language::Anchor,
 2739        cx: &App,
 2740    ) -> bool {
 2741        let snapshot = buffer.read(cx).snapshot();
 2742        let settings = snapshot.settings_at(buffer_position, cx);
 2743
 2744        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2745            return false;
 2746        };
 2747
 2748        scope.override_name().map_or(false, |scope_name| {
 2749            settings
 2750                .edit_predictions_disabled_in
 2751                .iter()
 2752                .any(|s| s == scope_name)
 2753        })
 2754    }
 2755
 2756    pub fn set_use_modal_editing(&mut self, to: bool) {
 2757        self.use_modal_editing = to;
 2758    }
 2759
 2760    pub fn use_modal_editing(&self) -> bool {
 2761        self.use_modal_editing
 2762    }
 2763
 2764    fn selections_did_change(
 2765        &mut self,
 2766        local: bool,
 2767        old_cursor_position: &Anchor,
 2768        effects: SelectionEffects,
 2769        window: &mut Window,
 2770        cx: &mut Context<Self>,
 2771    ) {
 2772        window.invalidate_character_coordinates();
 2773
 2774        // Copy selections to primary selection buffer
 2775        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2776        if local {
 2777            let selections = self.selections.all::<usize>(cx);
 2778            let buffer_handle = self.buffer.read(cx).read(cx);
 2779
 2780            let mut text = String::new();
 2781            for (index, selection) in selections.iter().enumerate() {
 2782                let text_for_selection = buffer_handle
 2783                    .text_for_range(selection.start..selection.end)
 2784                    .collect::<String>();
 2785
 2786                text.push_str(&text_for_selection);
 2787                if index != selections.len() - 1 {
 2788                    text.push('\n');
 2789                }
 2790            }
 2791
 2792            if !text.is_empty() {
 2793                cx.write_to_primary(ClipboardItem::new_string(text));
 2794            }
 2795        }
 2796
 2797        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2798            self.buffer.update(cx, |buffer, cx| {
 2799                buffer.set_active_selections(
 2800                    &self.selections.disjoint_anchors(),
 2801                    self.selections.line_mode,
 2802                    self.cursor_shape,
 2803                    cx,
 2804                )
 2805            });
 2806        }
 2807        let display_map = self
 2808            .display_map
 2809            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2810        let buffer = &display_map.buffer_snapshot;
 2811        if self.selections.count() == 1 {
 2812            self.add_selections_state = None;
 2813        }
 2814        self.select_next_state = None;
 2815        self.select_prev_state = None;
 2816        self.select_syntax_node_history.try_clear();
 2817        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2818        self.snippet_stack
 2819            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2820        self.take_rename(false, window, cx);
 2821
 2822        let newest_selection = self.selections.newest_anchor();
 2823        let new_cursor_position = newest_selection.head();
 2824        let selection_start = newest_selection.start;
 2825
 2826        if effects.nav_history {
 2827            self.push_to_nav_history(
 2828                *old_cursor_position,
 2829                Some(new_cursor_position.to_point(buffer)),
 2830                false,
 2831                cx,
 2832            );
 2833        }
 2834
 2835        if local {
 2836            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2837                if !self.registered_buffers.contains_key(&buffer_id) {
 2838                    if let Some(project) = self.project.as_ref() {
 2839                        project.update(cx, |project, cx| {
 2840                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2841                                return;
 2842                            };
 2843                            self.registered_buffers.insert(
 2844                                buffer_id,
 2845                                project.register_buffer_with_language_servers(&buffer, cx),
 2846                            );
 2847                        })
 2848                    }
 2849                }
 2850            }
 2851
 2852            let mut context_menu = self.context_menu.borrow_mut();
 2853            let completion_menu = match context_menu.as_ref() {
 2854                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2855                Some(CodeContextMenu::CodeActions(_)) => {
 2856                    *context_menu = None;
 2857                    None
 2858                }
 2859                None => None,
 2860            };
 2861            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2862            drop(context_menu);
 2863
 2864            if effects.completions {
 2865                if let Some(completion_position) = completion_position {
 2866                    let start_offset = selection_start.to_offset(buffer);
 2867                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2868                    let continue_showing = if position_matches {
 2869                        if self.snippet_stack.is_empty() {
 2870                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2871                        } else {
 2872                            // Snippet choices can be shown even when the cursor is in whitespace.
 2873                            // Dismissing the menu when actions like backspace
 2874                            true
 2875                        }
 2876                    } else {
 2877                        false
 2878                    };
 2879
 2880                    if continue_showing {
 2881                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2882                    } else {
 2883                        self.hide_context_menu(window, cx);
 2884                    }
 2885                }
 2886            }
 2887
 2888            hide_hover(self, cx);
 2889
 2890            if old_cursor_position.to_display_point(&display_map).row()
 2891                != new_cursor_position.to_display_point(&display_map).row()
 2892            {
 2893                self.available_code_actions.take();
 2894            }
 2895            self.refresh_code_actions(window, cx);
 2896            self.refresh_document_highlights(cx);
 2897            self.refresh_selected_text_highlights(false, window, cx);
 2898            refresh_matching_bracket_highlights(self, window, cx);
 2899            self.update_visible_inline_completion(window, cx);
 2900            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2901            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2902            self.inline_blame_popover.take();
 2903            if self.git_blame_inline_enabled {
 2904                self.start_inline_blame_timer(window, cx);
 2905            }
 2906        }
 2907
 2908        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2909        cx.emit(EditorEvent::SelectionsChanged { local });
 2910
 2911        let selections = &self.selections.disjoint;
 2912        if selections.len() == 1 {
 2913            cx.emit(SearchEvent::ActiveMatchChanged)
 2914        }
 2915        if local {
 2916            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2917                let inmemory_selections = selections
 2918                    .iter()
 2919                    .map(|s| {
 2920                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2921                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2922                    })
 2923                    .collect();
 2924                self.update_restoration_data(cx, |data| {
 2925                    data.selections = inmemory_selections;
 2926                });
 2927
 2928                if WorkspaceSettings::get(None, cx).restore_on_startup
 2929                    != RestoreOnStartupBehavior::None
 2930                {
 2931                    if let Some(workspace_id) =
 2932                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2933                    {
 2934                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2935                        let selections = selections.clone();
 2936                        let background_executor = cx.background_executor().clone();
 2937                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2938                        self.serialize_selections = cx.background_spawn(async move {
 2939                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2940                    let db_selections = selections
 2941                        .iter()
 2942                        .map(|selection| {
 2943                            (
 2944                                selection.start.to_offset(&snapshot),
 2945                                selection.end.to_offset(&snapshot),
 2946                            )
 2947                        })
 2948                        .collect();
 2949
 2950                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2951                        .await
 2952                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2953                        .log_err();
 2954                });
 2955                    }
 2956                }
 2957            }
 2958        }
 2959
 2960        cx.notify();
 2961    }
 2962
 2963    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2964        use text::ToOffset as _;
 2965        use text::ToPoint as _;
 2966
 2967        if self.mode.is_minimap()
 2968            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2969        {
 2970            return;
 2971        }
 2972
 2973        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2974            return;
 2975        };
 2976
 2977        let snapshot = singleton.read(cx).snapshot();
 2978        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2979            let display_snapshot = display_map.snapshot(cx);
 2980
 2981            display_snapshot
 2982                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2983                .map(|fold| {
 2984                    fold.range.start.text_anchor.to_point(&snapshot)
 2985                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2986                })
 2987                .collect()
 2988        });
 2989        self.update_restoration_data(cx, |data| {
 2990            data.folds = inmemory_folds;
 2991        });
 2992
 2993        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2994            return;
 2995        };
 2996        let background_executor = cx.background_executor().clone();
 2997        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2998        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2999            display_map
 3000                .snapshot(cx)
 3001                .folds_in_range(0..snapshot.len())
 3002                .map(|fold| {
 3003                    (
 3004                        fold.range.start.text_anchor.to_offset(&snapshot),
 3005                        fold.range.end.text_anchor.to_offset(&snapshot),
 3006                    )
 3007                })
 3008                .collect()
 3009        });
 3010        self.serialize_folds = cx.background_spawn(async move {
 3011            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3012            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3013                .await
 3014                .with_context(|| {
 3015                    format!(
 3016                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3017                    )
 3018                })
 3019                .log_err();
 3020        });
 3021    }
 3022
 3023    pub fn sync_selections(
 3024        &mut self,
 3025        other: Entity<Editor>,
 3026        cx: &mut Context<Self>,
 3027    ) -> gpui::Subscription {
 3028        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3029        self.selections.change_with(cx, |selections| {
 3030            selections.select_anchors(other_selections);
 3031        });
 3032
 3033        let other_subscription =
 3034            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3035                EditorEvent::SelectionsChanged { local: true } => {
 3036                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3037                    if other_selections.is_empty() {
 3038                        return;
 3039                    }
 3040                    this.selections.change_with(cx, |selections| {
 3041                        selections.select_anchors(other_selections);
 3042                    });
 3043                }
 3044                _ => {}
 3045            });
 3046
 3047        let this_subscription =
 3048            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3049                EditorEvent::SelectionsChanged { local: true } => {
 3050                    let these_selections = this.selections.disjoint.to_vec();
 3051                    if these_selections.is_empty() {
 3052                        return;
 3053                    }
 3054                    other.update(cx, |other_editor, cx| {
 3055                        other_editor.selections.change_with(cx, |selections| {
 3056                            selections.select_anchors(these_selections);
 3057                        })
 3058                    });
 3059                }
 3060                _ => {}
 3061            });
 3062
 3063        Subscription::join(other_subscription, this_subscription)
 3064    }
 3065
 3066    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3067    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3068    /// effects of selection change occur at the end of the transaction.
 3069    pub fn change_selections<R>(
 3070        &mut self,
 3071        effects: impl Into<SelectionEffects>,
 3072        window: &mut Window,
 3073        cx: &mut Context<Self>,
 3074        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3075    ) -> R {
 3076        let effects = effects.into();
 3077        if let Some(state) = &mut self.deferred_selection_effects_state {
 3078            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3079            state.effects.completions = effects.completions;
 3080            state.effects.nav_history |= effects.nav_history;
 3081            let (changed, result) = self.selections.change_with(cx, change);
 3082            state.changed |= changed;
 3083            return result;
 3084        }
 3085        let mut state = DeferredSelectionEffectsState {
 3086            changed: false,
 3087            effects,
 3088            old_cursor_position: self.selections.newest_anchor().head(),
 3089            history_entry: SelectionHistoryEntry {
 3090                selections: self.selections.disjoint_anchors(),
 3091                select_next_state: self.select_next_state.clone(),
 3092                select_prev_state: self.select_prev_state.clone(),
 3093                add_selections_state: self.add_selections_state.clone(),
 3094            },
 3095        };
 3096        let (changed, result) = self.selections.change_with(cx, change);
 3097        state.changed = state.changed || changed;
 3098        if self.defer_selection_effects {
 3099            self.deferred_selection_effects_state = Some(state);
 3100        } else {
 3101            self.apply_selection_effects(state, window, cx);
 3102        }
 3103        result
 3104    }
 3105
 3106    /// Defers the effects of selection change, so that the effects of multiple calls to
 3107    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3108    /// to selection history and the state of popovers based on selection position aren't
 3109    /// erroneously updated.
 3110    pub fn with_selection_effects_deferred<R>(
 3111        &mut self,
 3112        window: &mut Window,
 3113        cx: &mut Context<Self>,
 3114        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3115    ) -> R {
 3116        let already_deferred = self.defer_selection_effects;
 3117        self.defer_selection_effects = true;
 3118        let result = update(self, window, cx);
 3119        if !already_deferred {
 3120            self.defer_selection_effects = false;
 3121            if let Some(state) = self.deferred_selection_effects_state.take() {
 3122                self.apply_selection_effects(state, window, cx);
 3123            }
 3124        }
 3125        result
 3126    }
 3127
 3128    fn apply_selection_effects(
 3129        &mut self,
 3130        state: DeferredSelectionEffectsState,
 3131        window: &mut Window,
 3132        cx: &mut Context<Self>,
 3133    ) {
 3134        if state.changed {
 3135            self.selection_history.push(state.history_entry);
 3136
 3137            if let Some(autoscroll) = state.effects.scroll {
 3138                self.request_autoscroll(autoscroll, cx);
 3139            }
 3140
 3141            let old_cursor_position = &state.old_cursor_position;
 3142
 3143            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3144
 3145            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3146                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3147            }
 3148        }
 3149    }
 3150
 3151    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3152    where
 3153        I: IntoIterator<Item = (Range<S>, T)>,
 3154        S: ToOffset,
 3155        T: Into<Arc<str>>,
 3156    {
 3157        if self.read_only(cx) {
 3158            return;
 3159        }
 3160
 3161        self.buffer
 3162            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3163    }
 3164
 3165    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3166    where
 3167        I: IntoIterator<Item = (Range<S>, T)>,
 3168        S: ToOffset,
 3169        T: Into<Arc<str>>,
 3170    {
 3171        if self.read_only(cx) {
 3172            return;
 3173        }
 3174
 3175        self.buffer.update(cx, |buffer, cx| {
 3176            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3177        });
 3178    }
 3179
 3180    pub fn edit_with_block_indent<I, S, T>(
 3181        &mut self,
 3182        edits: I,
 3183        original_indent_columns: Vec<Option<u32>>,
 3184        cx: &mut Context<Self>,
 3185    ) where
 3186        I: IntoIterator<Item = (Range<S>, T)>,
 3187        S: ToOffset,
 3188        T: Into<Arc<str>>,
 3189    {
 3190        if self.read_only(cx) {
 3191            return;
 3192        }
 3193
 3194        self.buffer.update(cx, |buffer, cx| {
 3195            buffer.edit(
 3196                edits,
 3197                Some(AutoindentMode::Block {
 3198                    original_indent_columns,
 3199                }),
 3200                cx,
 3201            )
 3202        });
 3203    }
 3204
 3205    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3206        self.hide_context_menu(window, cx);
 3207
 3208        match phase {
 3209            SelectPhase::Begin {
 3210                position,
 3211                add,
 3212                click_count,
 3213            } => self.begin_selection(position, add, click_count, window, cx),
 3214            SelectPhase::BeginColumnar {
 3215                position,
 3216                goal_column,
 3217                reset,
 3218            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3219            SelectPhase::Extend {
 3220                position,
 3221                click_count,
 3222            } => self.extend_selection(position, click_count, window, cx),
 3223            SelectPhase::Update {
 3224                position,
 3225                goal_column,
 3226                scroll_delta,
 3227            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3228            SelectPhase::End => self.end_selection(window, cx),
 3229        }
 3230    }
 3231
 3232    fn extend_selection(
 3233        &mut self,
 3234        position: DisplayPoint,
 3235        click_count: usize,
 3236        window: &mut Window,
 3237        cx: &mut Context<Self>,
 3238    ) {
 3239        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3240        let tail = self.selections.newest::<usize>(cx).tail();
 3241        self.begin_selection(position, false, click_count, window, cx);
 3242
 3243        let position = position.to_offset(&display_map, Bias::Left);
 3244        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3245
 3246        let mut pending_selection = self
 3247            .selections
 3248            .pending_anchor()
 3249            .expect("extend_selection not called with pending selection");
 3250        if position >= tail {
 3251            pending_selection.start = tail_anchor;
 3252        } else {
 3253            pending_selection.end = tail_anchor;
 3254            pending_selection.reversed = true;
 3255        }
 3256
 3257        let mut pending_mode = self.selections.pending_mode().unwrap();
 3258        match &mut pending_mode {
 3259            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3260            _ => {}
 3261        }
 3262
 3263        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3264            SelectionEffects::scroll(Autoscroll::fit())
 3265        } else {
 3266            SelectionEffects::no_scroll()
 3267        };
 3268
 3269        self.change_selections(effects, window, cx, |s| {
 3270            s.set_pending(pending_selection, pending_mode)
 3271        });
 3272    }
 3273
 3274    fn begin_selection(
 3275        &mut self,
 3276        position: DisplayPoint,
 3277        add: bool,
 3278        click_count: usize,
 3279        window: &mut Window,
 3280        cx: &mut Context<Self>,
 3281    ) {
 3282        if !self.focus_handle.is_focused(window) {
 3283            self.last_focused_descendant = None;
 3284            window.focus(&self.focus_handle);
 3285        }
 3286
 3287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3288        let buffer = &display_map.buffer_snapshot;
 3289        let position = display_map.clip_point(position, Bias::Left);
 3290
 3291        let start;
 3292        let end;
 3293        let mode;
 3294        let mut auto_scroll;
 3295        match click_count {
 3296            1 => {
 3297                start = buffer.anchor_before(position.to_point(&display_map));
 3298                end = start;
 3299                mode = SelectMode::Character;
 3300                auto_scroll = true;
 3301            }
 3302            2 => {
 3303                let range = movement::surrounding_word(&display_map, position);
 3304                start = buffer.anchor_before(range.start.to_point(&display_map));
 3305                end = buffer.anchor_before(range.end.to_point(&display_map));
 3306                mode = SelectMode::Word(start..end);
 3307                auto_scroll = true;
 3308            }
 3309            3 => {
 3310                let position = display_map
 3311                    .clip_point(position, Bias::Left)
 3312                    .to_point(&display_map);
 3313                let line_start = display_map.prev_line_boundary(position).0;
 3314                let next_line_start = buffer.clip_point(
 3315                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3316                    Bias::Left,
 3317                );
 3318                start = buffer.anchor_before(line_start);
 3319                end = buffer.anchor_before(next_line_start);
 3320                mode = SelectMode::Line(start..end);
 3321                auto_scroll = true;
 3322            }
 3323            _ => {
 3324                start = buffer.anchor_before(0);
 3325                end = buffer.anchor_before(buffer.len());
 3326                mode = SelectMode::All;
 3327                auto_scroll = false;
 3328            }
 3329        }
 3330        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3331
 3332        let point_to_delete: Option<usize> = {
 3333            let selected_points: Vec<Selection<Point>> =
 3334                self.selections.disjoint_in_range(start..end, cx);
 3335
 3336            if !add || click_count > 1 {
 3337                None
 3338            } else if !selected_points.is_empty() {
 3339                Some(selected_points[0].id)
 3340            } else {
 3341                let clicked_point_already_selected =
 3342                    self.selections.disjoint.iter().find(|selection| {
 3343                        selection.start.to_point(buffer) == start.to_point(buffer)
 3344                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3345                    });
 3346
 3347                clicked_point_already_selected.map(|selection| selection.id)
 3348            }
 3349        };
 3350
 3351        let selections_count = self.selections.count();
 3352
 3353        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3354            if let Some(point_to_delete) = point_to_delete {
 3355                s.delete(point_to_delete);
 3356
 3357                if selections_count == 1 {
 3358                    s.set_pending_anchor_range(start..end, mode);
 3359                }
 3360            } else {
 3361                if !add {
 3362                    s.clear_disjoint();
 3363                }
 3364
 3365                s.set_pending_anchor_range(start..end, mode);
 3366            }
 3367        });
 3368    }
 3369
 3370    fn begin_columnar_selection(
 3371        &mut self,
 3372        position: DisplayPoint,
 3373        goal_column: u32,
 3374        reset: bool,
 3375        window: &mut Window,
 3376        cx: &mut Context<Self>,
 3377    ) {
 3378        if !self.focus_handle.is_focused(window) {
 3379            self.last_focused_descendant = None;
 3380            window.focus(&self.focus_handle);
 3381        }
 3382
 3383        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3384
 3385        if reset {
 3386            let pointer_position = display_map
 3387                .buffer_snapshot
 3388                .anchor_before(position.to_point(&display_map));
 3389
 3390            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3391                s.clear_disjoint();
 3392                s.set_pending_anchor_range(
 3393                    pointer_position..pointer_position,
 3394                    SelectMode::Character,
 3395                );
 3396            });
 3397            if position.column() != goal_column {
 3398                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3399            } else {
 3400                self.columnar_display_point = None;
 3401            }
 3402        }
 3403
 3404        let tail = self.selections.newest::<Point>(cx).tail();
 3405        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3406
 3407        if !reset {
 3408            self.columnar_display_point = None;
 3409            self.select_columns(
 3410                tail.to_display_point(&display_map),
 3411                position,
 3412                goal_column,
 3413                &display_map,
 3414                window,
 3415                cx,
 3416            );
 3417        }
 3418    }
 3419
 3420    fn update_selection(
 3421        &mut self,
 3422        position: DisplayPoint,
 3423        goal_column: u32,
 3424        scroll_delta: gpui::Point<f32>,
 3425        window: &mut Window,
 3426        cx: &mut Context<Self>,
 3427    ) {
 3428        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3429
 3430        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3431            let tail = self
 3432                .columnar_display_point
 3433                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3434            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3435        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3436            let buffer = self.buffer.read(cx).snapshot(cx);
 3437            let head;
 3438            let tail;
 3439            let mode = self.selections.pending_mode().unwrap();
 3440            match &mode {
 3441                SelectMode::Character => {
 3442                    head = position.to_point(&display_map);
 3443                    tail = pending.tail().to_point(&buffer);
 3444                }
 3445                SelectMode::Word(original_range) => {
 3446                    let original_display_range = original_range.start.to_display_point(&display_map)
 3447                        ..original_range.end.to_display_point(&display_map);
 3448                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3449                        ..original_display_range.end.to_point(&display_map);
 3450                    if movement::is_inside_word(&display_map, position)
 3451                        || original_display_range.contains(&position)
 3452                    {
 3453                        let word_range = movement::surrounding_word(&display_map, position);
 3454                        if word_range.start < original_display_range.start {
 3455                            head = word_range.start.to_point(&display_map);
 3456                        } else {
 3457                            head = word_range.end.to_point(&display_map);
 3458                        }
 3459                    } else {
 3460                        head = position.to_point(&display_map);
 3461                    }
 3462
 3463                    if head <= original_buffer_range.start {
 3464                        tail = original_buffer_range.end;
 3465                    } else {
 3466                        tail = original_buffer_range.start;
 3467                    }
 3468                }
 3469                SelectMode::Line(original_range) => {
 3470                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3471
 3472                    let position = display_map
 3473                        .clip_point(position, Bias::Left)
 3474                        .to_point(&display_map);
 3475                    let line_start = display_map.prev_line_boundary(position).0;
 3476                    let next_line_start = buffer.clip_point(
 3477                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3478                        Bias::Left,
 3479                    );
 3480
 3481                    if line_start < original_range.start {
 3482                        head = line_start
 3483                    } else {
 3484                        head = next_line_start
 3485                    }
 3486
 3487                    if head <= original_range.start {
 3488                        tail = original_range.end;
 3489                    } else {
 3490                        tail = original_range.start;
 3491                    }
 3492                }
 3493                SelectMode::All => {
 3494                    return;
 3495                }
 3496            };
 3497
 3498            if head < tail {
 3499                pending.start = buffer.anchor_before(head);
 3500                pending.end = buffer.anchor_before(tail);
 3501                pending.reversed = true;
 3502            } else {
 3503                pending.start = buffer.anchor_before(tail);
 3504                pending.end = buffer.anchor_before(head);
 3505                pending.reversed = false;
 3506            }
 3507
 3508            self.change_selections(None, window, cx, |s| {
 3509                s.set_pending(pending, mode);
 3510            });
 3511        } else {
 3512            log::error!("update_selection dispatched with no pending selection");
 3513            return;
 3514        }
 3515
 3516        self.apply_scroll_delta(scroll_delta, window, cx);
 3517        cx.notify();
 3518    }
 3519
 3520    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3521        self.columnar_selection_tail.take();
 3522        if self.selections.pending_anchor().is_some() {
 3523            let selections = self.selections.all::<usize>(cx);
 3524            self.change_selections(None, window, cx, |s| {
 3525                s.select(selections);
 3526                s.clear_pending();
 3527            });
 3528        }
 3529    }
 3530
 3531    fn select_columns(
 3532        &mut self,
 3533        tail: DisplayPoint,
 3534        head: DisplayPoint,
 3535        goal_column: u32,
 3536        display_map: &DisplaySnapshot,
 3537        window: &mut Window,
 3538        cx: &mut Context<Self>,
 3539    ) {
 3540        let start_row = cmp::min(tail.row(), head.row());
 3541        let end_row = cmp::max(tail.row(), head.row());
 3542        let start_column = cmp::min(tail.column(), goal_column);
 3543        let end_column = cmp::max(tail.column(), goal_column);
 3544        let reversed = start_column < tail.column();
 3545
 3546        let selection_ranges = (start_row.0..=end_row.0)
 3547            .map(DisplayRow)
 3548            .filter_map(|row| {
 3549                if !display_map.is_block_line(row) {
 3550                    let start = display_map
 3551                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3552                        .to_point(display_map);
 3553                    let end = display_map
 3554                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3555                        .to_point(display_map);
 3556                    if reversed {
 3557                        Some(end..start)
 3558                    } else {
 3559                        Some(start..end)
 3560                    }
 3561                } else {
 3562                    None
 3563                }
 3564            })
 3565            .collect::<Vec<_>>();
 3566
 3567        let mut non_empty_ranges = selection_ranges
 3568            .iter()
 3569            .filter(|selection_range| selection_range.start != selection_range.end)
 3570            .peekable();
 3571
 3572        let ranges = if non_empty_ranges.peek().is_some() {
 3573            non_empty_ranges.cloned().collect()
 3574        } else {
 3575            selection_ranges
 3576        };
 3577
 3578        self.change_selections(None, window, cx, |s| {
 3579            s.select_ranges(ranges);
 3580        });
 3581        cx.notify();
 3582    }
 3583
 3584    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3585        self.selections
 3586            .all_adjusted(cx)
 3587            .iter()
 3588            .any(|selection| !selection.is_empty())
 3589    }
 3590
 3591    pub fn has_pending_nonempty_selection(&self) -> bool {
 3592        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3593            Some(Selection { start, end, .. }) => start != end,
 3594            None => false,
 3595        };
 3596
 3597        pending_nonempty_selection
 3598            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3599    }
 3600
 3601    pub fn has_pending_selection(&self) -> bool {
 3602        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3603    }
 3604
 3605    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3606        self.selection_mark_mode = false;
 3607        self.selection_drag_state = SelectionDragState::None;
 3608
 3609        if self.clear_expanded_diff_hunks(cx) {
 3610            cx.notify();
 3611            return;
 3612        }
 3613        if self.dismiss_menus_and_popups(true, window, cx) {
 3614            return;
 3615        }
 3616
 3617        if self.mode.is_full()
 3618            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3619        {
 3620            return;
 3621        }
 3622
 3623        cx.propagate();
 3624    }
 3625
 3626    pub fn dismiss_menus_and_popups(
 3627        &mut self,
 3628        is_user_requested: bool,
 3629        window: &mut Window,
 3630        cx: &mut Context<Self>,
 3631    ) -> bool {
 3632        if self.take_rename(false, window, cx).is_some() {
 3633            return true;
 3634        }
 3635
 3636        if hide_hover(self, cx) {
 3637            return true;
 3638        }
 3639
 3640        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3641            return true;
 3642        }
 3643
 3644        if self.hide_context_menu(window, cx).is_some() {
 3645            return true;
 3646        }
 3647
 3648        if self.mouse_context_menu.take().is_some() {
 3649            return true;
 3650        }
 3651
 3652        if is_user_requested && self.discard_inline_completion(true, cx) {
 3653            return true;
 3654        }
 3655
 3656        if self.snippet_stack.pop().is_some() {
 3657            return true;
 3658        }
 3659
 3660        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3661            self.dismiss_diagnostics(cx);
 3662            return true;
 3663        }
 3664
 3665        false
 3666    }
 3667
 3668    fn linked_editing_ranges_for(
 3669        &self,
 3670        selection: Range<text::Anchor>,
 3671        cx: &App,
 3672    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3673        if self.linked_edit_ranges.is_empty() {
 3674            return None;
 3675        }
 3676        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3677            selection.end.buffer_id.and_then(|end_buffer_id| {
 3678                if selection.start.buffer_id != Some(end_buffer_id) {
 3679                    return None;
 3680                }
 3681                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3682                let snapshot = buffer.read(cx).snapshot();
 3683                self.linked_edit_ranges
 3684                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3685                    .map(|ranges| (ranges, snapshot, buffer))
 3686            })?;
 3687        use text::ToOffset as TO;
 3688        // find offset from the start of current range to current cursor position
 3689        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3690
 3691        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3692        let start_difference = start_offset - start_byte_offset;
 3693        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3694        let end_difference = end_offset - start_byte_offset;
 3695        // Current range has associated linked ranges.
 3696        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3697        for range in linked_ranges.iter() {
 3698            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3699            let end_offset = start_offset + end_difference;
 3700            let start_offset = start_offset + start_difference;
 3701            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3702                continue;
 3703            }
 3704            if self.selections.disjoint_anchor_ranges().any(|s| {
 3705                if s.start.buffer_id != selection.start.buffer_id
 3706                    || s.end.buffer_id != selection.end.buffer_id
 3707                {
 3708                    return false;
 3709                }
 3710                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3711                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3712            }) {
 3713                continue;
 3714            }
 3715            let start = buffer_snapshot.anchor_after(start_offset);
 3716            let end = buffer_snapshot.anchor_after(end_offset);
 3717            linked_edits
 3718                .entry(buffer.clone())
 3719                .or_default()
 3720                .push(start..end);
 3721        }
 3722        Some(linked_edits)
 3723    }
 3724
 3725    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3726        let text: Arc<str> = text.into();
 3727
 3728        if self.read_only(cx) {
 3729            return;
 3730        }
 3731
 3732        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3733
 3734        let selections = self.selections.all_adjusted(cx);
 3735        let mut bracket_inserted = false;
 3736        let mut edits = Vec::new();
 3737        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3738        let mut new_selections = Vec::with_capacity(selections.len());
 3739        let mut new_autoclose_regions = Vec::new();
 3740        let snapshot = self.buffer.read(cx).read(cx);
 3741        let mut clear_linked_edit_ranges = false;
 3742
 3743        for (selection, autoclose_region) in
 3744            self.selections_with_autoclose_regions(selections, &snapshot)
 3745        {
 3746            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3747                // Determine if the inserted text matches the opening or closing
 3748                // bracket of any of this language's bracket pairs.
 3749                let mut bracket_pair = None;
 3750                let mut is_bracket_pair_start = false;
 3751                let mut is_bracket_pair_end = false;
 3752                if !text.is_empty() {
 3753                    let mut bracket_pair_matching_end = None;
 3754                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3755                    //  and they are removing the character that triggered IME popup.
 3756                    for (pair, enabled) in scope.brackets() {
 3757                        if !pair.close && !pair.surround {
 3758                            continue;
 3759                        }
 3760
 3761                        if enabled && pair.start.ends_with(text.as_ref()) {
 3762                            let prefix_len = pair.start.len() - text.len();
 3763                            let preceding_text_matches_prefix = prefix_len == 0
 3764                                || (selection.start.column >= (prefix_len as u32)
 3765                                    && snapshot.contains_str_at(
 3766                                        Point::new(
 3767                                            selection.start.row,
 3768                                            selection.start.column - (prefix_len as u32),
 3769                                        ),
 3770                                        &pair.start[..prefix_len],
 3771                                    ));
 3772                            if preceding_text_matches_prefix {
 3773                                bracket_pair = Some(pair.clone());
 3774                                is_bracket_pair_start = true;
 3775                                break;
 3776                            }
 3777                        }
 3778                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3779                        {
 3780                            // take first bracket pair matching end, but don't break in case a later bracket
 3781                            // pair matches start
 3782                            bracket_pair_matching_end = Some(pair.clone());
 3783                        }
 3784                    }
 3785                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3786                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3787                        is_bracket_pair_end = true;
 3788                    }
 3789                }
 3790
 3791                if let Some(bracket_pair) = bracket_pair {
 3792                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3793                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3794                    let auto_surround =
 3795                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3796                    if selection.is_empty() {
 3797                        if is_bracket_pair_start {
 3798                            // If the inserted text is a suffix of an opening bracket and the
 3799                            // selection is preceded by the rest of the opening bracket, then
 3800                            // insert the closing bracket.
 3801                            let following_text_allows_autoclose = snapshot
 3802                                .chars_at(selection.start)
 3803                                .next()
 3804                                .map_or(true, |c| scope.should_autoclose_before(c));
 3805
 3806                            let preceding_text_allows_autoclose = selection.start.column == 0
 3807                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3808                                    true,
 3809                                    |c| {
 3810                                        bracket_pair.start != bracket_pair.end
 3811                                            || !snapshot
 3812                                                .char_classifier_at(selection.start)
 3813                                                .is_word(c)
 3814                                    },
 3815                                );
 3816
 3817                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3818                                && bracket_pair.start.len() == 1
 3819                            {
 3820                                let target = bracket_pair.start.chars().next().unwrap();
 3821                                let current_line_count = snapshot
 3822                                    .reversed_chars_at(selection.start)
 3823                                    .take_while(|&c| c != '\n')
 3824                                    .filter(|&c| c == target)
 3825                                    .count();
 3826                                current_line_count % 2 == 1
 3827                            } else {
 3828                                false
 3829                            };
 3830
 3831                            if autoclose
 3832                                && bracket_pair.close
 3833                                && following_text_allows_autoclose
 3834                                && preceding_text_allows_autoclose
 3835                                && !is_closing_quote
 3836                            {
 3837                                let anchor = snapshot.anchor_before(selection.end);
 3838                                new_selections.push((selection.map(|_| anchor), text.len()));
 3839                                new_autoclose_regions.push((
 3840                                    anchor,
 3841                                    text.len(),
 3842                                    selection.id,
 3843                                    bracket_pair.clone(),
 3844                                ));
 3845                                edits.push((
 3846                                    selection.range(),
 3847                                    format!("{}{}", text, bracket_pair.end).into(),
 3848                                ));
 3849                                bracket_inserted = true;
 3850                                continue;
 3851                            }
 3852                        }
 3853
 3854                        if let Some(region) = autoclose_region {
 3855                            // If the selection is followed by an auto-inserted closing bracket,
 3856                            // then don't insert that closing bracket again; just move the selection
 3857                            // past the closing bracket.
 3858                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3859                                && text.as_ref() == region.pair.end.as_str();
 3860                            if should_skip {
 3861                                let anchor = snapshot.anchor_after(selection.end);
 3862                                new_selections
 3863                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3864                                continue;
 3865                            }
 3866                        }
 3867
 3868                        let always_treat_brackets_as_autoclosed = snapshot
 3869                            .language_settings_at(selection.start, cx)
 3870                            .always_treat_brackets_as_autoclosed;
 3871                        if always_treat_brackets_as_autoclosed
 3872                            && is_bracket_pair_end
 3873                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3874                        {
 3875                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3876                            // and the inserted text is a closing bracket and the selection is followed
 3877                            // by the closing bracket then move the selection past the closing bracket.
 3878                            let anchor = snapshot.anchor_after(selection.end);
 3879                            new_selections.push((selection.map(|_| anchor), text.len()));
 3880                            continue;
 3881                        }
 3882                    }
 3883                    // If an opening bracket is 1 character long and is typed while
 3884                    // text is selected, then surround that text with the bracket pair.
 3885                    else if auto_surround
 3886                        && bracket_pair.surround
 3887                        && is_bracket_pair_start
 3888                        && bracket_pair.start.chars().count() == 1
 3889                    {
 3890                        edits.push((selection.start..selection.start, text.clone()));
 3891                        edits.push((
 3892                            selection.end..selection.end,
 3893                            bracket_pair.end.as_str().into(),
 3894                        ));
 3895                        bracket_inserted = true;
 3896                        new_selections.push((
 3897                            Selection {
 3898                                id: selection.id,
 3899                                start: snapshot.anchor_after(selection.start),
 3900                                end: snapshot.anchor_before(selection.end),
 3901                                reversed: selection.reversed,
 3902                                goal: selection.goal,
 3903                            },
 3904                            0,
 3905                        ));
 3906                        continue;
 3907                    }
 3908                }
 3909            }
 3910
 3911            if self.auto_replace_emoji_shortcode
 3912                && selection.is_empty()
 3913                && text.as_ref().ends_with(':')
 3914            {
 3915                if let Some(possible_emoji_short_code) =
 3916                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3917                {
 3918                    if !possible_emoji_short_code.is_empty() {
 3919                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3920                            let emoji_shortcode_start = Point::new(
 3921                                selection.start.row,
 3922                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3923                            );
 3924
 3925                            // Remove shortcode from buffer
 3926                            edits.push((
 3927                                emoji_shortcode_start..selection.start,
 3928                                "".to_string().into(),
 3929                            ));
 3930                            new_selections.push((
 3931                                Selection {
 3932                                    id: selection.id,
 3933                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3934                                    end: snapshot.anchor_before(selection.start),
 3935                                    reversed: selection.reversed,
 3936                                    goal: selection.goal,
 3937                                },
 3938                                0,
 3939                            ));
 3940
 3941                            // Insert emoji
 3942                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3943                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3944                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3945
 3946                            continue;
 3947                        }
 3948                    }
 3949                }
 3950            }
 3951
 3952            // If not handling any auto-close operation, then just replace the selected
 3953            // text with the given input and move the selection to the end of the
 3954            // newly inserted text.
 3955            let anchor = snapshot.anchor_after(selection.end);
 3956            if !self.linked_edit_ranges.is_empty() {
 3957                let start_anchor = snapshot.anchor_before(selection.start);
 3958
 3959                let is_word_char = text.chars().next().map_or(true, |char| {
 3960                    let classifier = snapshot
 3961                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3962                        .ignore_punctuation(true);
 3963                    classifier.is_word(char)
 3964                });
 3965
 3966                if is_word_char {
 3967                    if let Some(ranges) = self
 3968                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3969                    {
 3970                        for (buffer, edits) in ranges {
 3971                            linked_edits
 3972                                .entry(buffer.clone())
 3973                                .or_default()
 3974                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3975                        }
 3976                    }
 3977                } else {
 3978                    clear_linked_edit_ranges = true;
 3979                }
 3980            }
 3981
 3982            new_selections.push((selection.map(|_| anchor), 0));
 3983            edits.push((selection.start..selection.end, text.clone()));
 3984        }
 3985
 3986        drop(snapshot);
 3987
 3988        self.transact(window, cx, |this, window, cx| {
 3989            if clear_linked_edit_ranges {
 3990                this.linked_edit_ranges.clear();
 3991            }
 3992            let initial_buffer_versions =
 3993                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3994
 3995            this.buffer.update(cx, |buffer, cx| {
 3996                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3997            });
 3998            for (buffer, edits) in linked_edits {
 3999                buffer.update(cx, |buffer, cx| {
 4000                    let snapshot = buffer.snapshot();
 4001                    let edits = edits
 4002                        .into_iter()
 4003                        .map(|(range, text)| {
 4004                            use text::ToPoint as TP;
 4005                            let end_point = TP::to_point(&range.end, &snapshot);
 4006                            let start_point = TP::to_point(&range.start, &snapshot);
 4007                            (start_point..end_point, text)
 4008                        })
 4009                        .sorted_by_key(|(range, _)| range.start);
 4010                    buffer.edit(edits, None, cx);
 4011                })
 4012            }
 4013            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4014            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4015            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4016            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4017                .zip(new_selection_deltas)
 4018                .map(|(selection, delta)| Selection {
 4019                    id: selection.id,
 4020                    start: selection.start + delta,
 4021                    end: selection.end + delta,
 4022                    reversed: selection.reversed,
 4023                    goal: SelectionGoal::None,
 4024                })
 4025                .collect::<Vec<_>>();
 4026
 4027            let mut i = 0;
 4028            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4029                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4030                let start = map.buffer_snapshot.anchor_before(position);
 4031                let end = map.buffer_snapshot.anchor_after(position);
 4032                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4033                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4034                        Ordering::Less => i += 1,
 4035                        Ordering::Greater => break,
 4036                        Ordering::Equal => {
 4037                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4038                                Ordering::Less => i += 1,
 4039                                Ordering::Equal => break,
 4040                                Ordering::Greater => break,
 4041                            }
 4042                        }
 4043                    }
 4044                }
 4045                this.autoclose_regions.insert(
 4046                    i,
 4047                    AutocloseRegion {
 4048                        selection_id,
 4049                        range: start..end,
 4050                        pair,
 4051                    },
 4052                );
 4053            }
 4054
 4055            let had_active_inline_completion = this.has_active_inline_completion();
 4056            this.change_selections(
 4057                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4058                window,
 4059                cx,
 4060                |s| s.select(new_selections),
 4061            );
 4062
 4063            if !bracket_inserted {
 4064                if let Some(on_type_format_task) =
 4065                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4066                {
 4067                    on_type_format_task.detach_and_log_err(cx);
 4068                }
 4069            }
 4070
 4071            let editor_settings = EditorSettings::get_global(cx);
 4072            if bracket_inserted
 4073                && (editor_settings.auto_signature_help
 4074                    || editor_settings.show_signature_help_after_edits)
 4075            {
 4076                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4077            }
 4078
 4079            let trigger_in_words =
 4080                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4081            if this.hard_wrap.is_some() {
 4082                let latest: Range<Point> = this.selections.newest(cx).range();
 4083                if latest.is_empty()
 4084                    && this
 4085                        .buffer()
 4086                        .read(cx)
 4087                        .snapshot(cx)
 4088                        .line_len(MultiBufferRow(latest.start.row))
 4089                        == latest.start.column
 4090                {
 4091                    this.rewrap_impl(
 4092                        RewrapOptions {
 4093                            override_language_settings: true,
 4094                            preserve_existing_whitespace: true,
 4095                        },
 4096                        cx,
 4097                    )
 4098                }
 4099            }
 4100            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4101            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4102            this.refresh_inline_completion(true, false, window, cx);
 4103            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4104        });
 4105    }
 4106
 4107    fn find_possible_emoji_shortcode_at_position(
 4108        snapshot: &MultiBufferSnapshot,
 4109        position: Point,
 4110    ) -> Option<String> {
 4111        let mut chars = Vec::new();
 4112        let mut found_colon = false;
 4113        for char in snapshot.reversed_chars_at(position).take(100) {
 4114            // Found a possible emoji shortcode in the middle of the buffer
 4115            if found_colon {
 4116                if char.is_whitespace() {
 4117                    chars.reverse();
 4118                    return Some(chars.iter().collect());
 4119                }
 4120                // If the previous character is not a whitespace, we are in the middle of a word
 4121                // and we only want to complete the shortcode if the word is made up of other emojis
 4122                let mut containing_word = String::new();
 4123                for ch in snapshot
 4124                    .reversed_chars_at(position)
 4125                    .skip(chars.len() + 1)
 4126                    .take(100)
 4127                {
 4128                    if ch.is_whitespace() {
 4129                        break;
 4130                    }
 4131                    containing_word.push(ch);
 4132                }
 4133                let containing_word = containing_word.chars().rev().collect::<String>();
 4134                if util::word_consists_of_emojis(containing_word.as_str()) {
 4135                    chars.reverse();
 4136                    return Some(chars.iter().collect());
 4137                }
 4138            }
 4139
 4140            if char.is_whitespace() || !char.is_ascii() {
 4141                return None;
 4142            }
 4143            if char == ':' {
 4144                found_colon = true;
 4145            } else {
 4146                chars.push(char);
 4147            }
 4148        }
 4149        // Found a possible emoji shortcode at the beginning of the buffer
 4150        chars.reverse();
 4151        Some(chars.iter().collect())
 4152    }
 4153
 4154    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4155        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4156        self.transact(window, cx, |this, window, cx| {
 4157            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4158                let selections = this.selections.all::<usize>(cx);
 4159                let multi_buffer = this.buffer.read(cx);
 4160                let buffer = multi_buffer.snapshot(cx);
 4161                selections
 4162                    .iter()
 4163                    .map(|selection| {
 4164                        let start_point = selection.start.to_point(&buffer);
 4165                        let mut existing_indent =
 4166                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4167                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4168                        let start = selection.start;
 4169                        let end = selection.end;
 4170                        let selection_is_empty = start == end;
 4171                        let language_scope = buffer.language_scope_at(start);
 4172                        let (
 4173                            comment_delimiter,
 4174                            doc_delimiter,
 4175                            insert_extra_newline,
 4176                            indent_on_newline,
 4177                            indent_on_extra_newline,
 4178                        ) = if let Some(language) = &language_scope {
 4179                            let mut insert_extra_newline =
 4180                                insert_extra_newline_brackets(&buffer, start..end, language)
 4181                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4182
 4183                            // Comment extension on newline is allowed only for cursor selections
 4184                            let comment_delimiter = maybe!({
 4185                                if !selection_is_empty {
 4186                                    return None;
 4187                                }
 4188
 4189                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4190                                    return None;
 4191                                }
 4192
 4193                                let delimiters = language.line_comment_prefixes();
 4194                                let max_len_of_delimiter =
 4195                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4196                                let (snapshot, range) =
 4197                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4198
 4199                                let num_of_whitespaces = snapshot
 4200                                    .chars_for_range(range.clone())
 4201                                    .take_while(|c| c.is_whitespace())
 4202                                    .count();
 4203                                let comment_candidate = snapshot
 4204                                    .chars_for_range(range)
 4205                                    .skip(num_of_whitespaces)
 4206                                    .take(max_len_of_delimiter)
 4207                                    .collect::<String>();
 4208                                let (delimiter, trimmed_len) = delimiters
 4209                                    .iter()
 4210                                    .filter_map(|delimiter| {
 4211                                        let prefix = delimiter.trim_end();
 4212                                        if comment_candidate.starts_with(prefix) {
 4213                                            Some((delimiter, prefix.len()))
 4214                                        } else {
 4215                                            None
 4216                                        }
 4217                                    })
 4218                                    .max_by_key(|(_, len)| *len)?;
 4219
 4220                                let cursor_is_placed_after_comment_marker =
 4221                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4222                                if cursor_is_placed_after_comment_marker {
 4223                                    Some(delimiter.clone())
 4224                                } else {
 4225                                    None
 4226                                }
 4227                            });
 4228
 4229                            let mut indent_on_newline = IndentSize::spaces(0);
 4230                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4231
 4232                            let doc_delimiter = maybe!({
 4233                                if !selection_is_empty {
 4234                                    return None;
 4235                                }
 4236
 4237                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4238                                    return None;
 4239                                }
 4240
 4241                                let DocumentationConfig {
 4242                                    start: start_tag,
 4243                                    end: end_tag,
 4244                                    prefix: delimiter,
 4245                                    tab_size: len,
 4246                                } = language.documentation()?;
 4247
 4248                                let is_within_block_comment = buffer
 4249                                    .language_scope_at(start_point)
 4250                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4251                                if !is_within_block_comment {
 4252                                    return None;
 4253                                }
 4254
 4255                                let (snapshot, range) =
 4256                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4257
 4258                                let num_of_whitespaces = snapshot
 4259                                    .chars_for_range(range.clone())
 4260                                    .take_while(|c| c.is_whitespace())
 4261                                    .count();
 4262
 4263                                // 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.
 4264                                let column = start_point.column;
 4265                                let cursor_is_after_start_tag = {
 4266                                    let start_tag_len = start_tag.len();
 4267                                    let start_tag_line = snapshot
 4268                                        .chars_for_range(range.clone())
 4269                                        .skip(num_of_whitespaces)
 4270                                        .take(start_tag_len)
 4271                                        .collect::<String>();
 4272                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4273                                        num_of_whitespaces + start_tag_len <= column as usize
 4274                                    } else {
 4275                                        false
 4276                                    }
 4277                                };
 4278
 4279                                let cursor_is_after_delimiter = {
 4280                                    let delimiter_trim = delimiter.trim_end();
 4281                                    let delimiter_line = snapshot
 4282                                        .chars_for_range(range.clone())
 4283                                        .skip(num_of_whitespaces)
 4284                                        .take(delimiter_trim.len())
 4285                                        .collect::<String>();
 4286                                    if delimiter_line.starts_with(delimiter_trim) {
 4287                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4288                                    } else {
 4289                                        false
 4290                                    }
 4291                                };
 4292
 4293                                let cursor_is_before_end_tag_if_exists = {
 4294                                    let mut char_position = 0u32;
 4295                                    let mut end_tag_offset = None;
 4296
 4297                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4298                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4299                                            let chars_before_match =
 4300                                                chunk[..byte_pos].chars().count() as u32;
 4301                                            end_tag_offset =
 4302                                                Some(char_position + chars_before_match);
 4303                                            break 'outer;
 4304                                        }
 4305                                        char_position += chunk.chars().count() as u32;
 4306                                    }
 4307
 4308                                    if let Some(end_tag_offset) = end_tag_offset {
 4309                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4310                                        if cursor_is_after_start_tag {
 4311                                            if cursor_is_before_end_tag {
 4312                                                insert_extra_newline = true;
 4313                                            }
 4314                                            let cursor_is_at_start_of_end_tag =
 4315                                                column == end_tag_offset;
 4316                                            if cursor_is_at_start_of_end_tag {
 4317                                                indent_on_extra_newline.len = (*len).into();
 4318                                            }
 4319                                        }
 4320                                        cursor_is_before_end_tag
 4321                                    } else {
 4322                                        true
 4323                                    }
 4324                                };
 4325
 4326                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4327                                    && cursor_is_before_end_tag_if_exists
 4328                                {
 4329                                    if cursor_is_after_start_tag {
 4330                                        indent_on_newline.len = (*len).into();
 4331                                    }
 4332                                    Some(delimiter.clone())
 4333                                } else {
 4334                                    None
 4335                                }
 4336                            });
 4337
 4338                            (
 4339                                comment_delimiter,
 4340                                doc_delimiter,
 4341                                insert_extra_newline,
 4342                                indent_on_newline,
 4343                                indent_on_extra_newline,
 4344                            )
 4345                        } else {
 4346                            (
 4347                                None,
 4348                                None,
 4349                                false,
 4350                                IndentSize::default(),
 4351                                IndentSize::default(),
 4352                            )
 4353                        };
 4354
 4355                        let prevent_auto_indent = doc_delimiter.is_some();
 4356                        let delimiter = comment_delimiter.or(doc_delimiter);
 4357
 4358                        let capacity_for_delimiter =
 4359                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4360                        let mut new_text = String::with_capacity(
 4361                            1 + capacity_for_delimiter
 4362                                + existing_indent.len as usize
 4363                                + indent_on_newline.len as usize
 4364                                + indent_on_extra_newline.len as usize,
 4365                        );
 4366                        new_text.push('\n');
 4367                        new_text.extend(existing_indent.chars());
 4368                        new_text.extend(indent_on_newline.chars());
 4369
 4370                        if let Some(delimiter) = &delimiter {
 4371                            new_text.push_str(delimiter);
 4372                        }
 4373
 4374                        if insert_extra_newline {
 4375                            new_text.push('\n');
 4376                            new_text.extend(existing_indent.chars());
 4377                            new_text.extend(indent_on_extra_newline.chars());
 4378                        }
 4379
 4380                        let anchor = buffer.anchor_after(end);
 4381                        let new_selection = selection.map(|_| anchor);
 4382                        (
 4383                            ((start..end, new_text), prevent_auto_indent),
 4384                            (insert_extra_newline, new_selection),
 4385                        )
 4386                    })
 4387                    .unzip()
 4388            };
 4389
 4390            let mut auto_indent_edits = Vec::new();
 4391            let mut edits = Vec::new();
 4392            for (edit, prevent_auto_indent) in edits_with_flags {
 4393                if prevent_auto_indent {
 4394                    edits.push(edit);
 4395                } else {
 4396                    auto_indent_edits.push(edit);
 4397                }
 4398            }
 4399            if !edits.is_empty() {
 4400                this.edit(edits, cx);
 4401            }
 4402            if !auto_indent_edits.is_empty() {
 4403                this.edit_with_autoindent(auto_indent_edits, cx);
 4404            }
 4405
 4406            let buffer = this.buffer.read(cx).snapshot(cx);
 4407            let new_selections = selection_info
 4408                .into_iter()
 4409                .map(|(extra_newline_inserted, new_selection)| {
 4410                    let mut cursor = new_selection.end.to_point(&buffer);
 4411                    if extra_newline_inserted {
 4412                        cursor.row -= 1;
 4413                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4414                    }
 4415                    new_selection.map(|_| cursor)
 4416                })
 4417                .collect();
 4418
 4419            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4420                s.select(new_selections)
 4421            });
 4422            this.refresh_inline_completion(true, false, window, cx);
 4423        });
 4424    }
 4425
 4426    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4427        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4428
 4429        let buffer = self.buffer.read(cx);
 4430        let snapshot = buffer.snapshot(cx);
 4431
 4432        let mut edits = Vec::new();
 4433        let mut rows = Vec::new();
 4434
 4435        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4436            let cursor = selection.head();
 4437            let row = cursor.row;
 4438
 4439            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4440
 4441            let newline = "\n".to_string();
 4442            edits.push((start_of_line..start_of_line, newline));
 4443
 4444            rows.push(row + rows_inserted as u32);
 4445        }
 4446
 4447        self.transact(window, cx, |editor, window, cx| {
 4448            editor.edit(edits, cx);
 4449
 4450            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4451                let mut index = 0;
 4452                s.move_cursors_with(|map, _, _| {
 4453                    let row = rows[index];
 4454                    index += 1;
 4455
 4456                    let point = Point::new(row, 0);
 4457                    let boundary = map.next_line_boundary(point).1;
 4458                    let clipped = map.clip_point(boundary, Bias::Left);
 4459
 4460                    (clipped, SelectionGoal::None)
 4461                });
 4462            });
 4463
 4464            let mut indent_edits = Vec::new();
 4465            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4466            for row in rows {
 4467                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4468                for (row, indent) in indents {
 4469                    if indent.len == 0 {
 4470                        continue;
 4471                    }
 4472
 4473                    let text = match indent.kind {
 4474                        IndentKind::Space => " ".repeat(indent.len as usize),
 4475                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4476                    };
 4477                    let point = Point::new(row.0, 0);
 4478                    indent_edits.push((point..point, text));
 4479                }
 4480            }
 4481            editor.edit(indent_edits, cx);
 4482        });
 4483    }
 4484
 4485    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4486        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4487
 4488        let buffer = self.buffer.read(cx);
 4489        let snapshot = buffer.snapshot(cx);
 4490
 4491        let mut edits = Vec::new();
 4492        let mut rows = Vec::new();
 4493        let mut rows_inserted = 0;
 4494
 4495        for selection in self.selections.all_adjusted(cx) {
 4496            let cursor = selection.head();
 4497            let row = cursor.row;
 4498
 4499            let point = Point::new(row + 1, 0);
 4500            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4501
 4502            let newline = "\n".to_string();
 4503            edits.push((start_of_line..start_of_line, newline));
 4504
 4505            rows_inserted += 1;
 4506            rows.push(row + rows_inserted);
 4507        }
 4508
 4509        self.transact(window, cx, |editor, window, cx| {
 4510            editor.edit(edits, cx);
 4511
 4512            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4513                let mut index = 0;
 4514                s.move_cursors_with(|map, _, _| {
 4515                    let row = rows[index];
 4516                    index += 1;
 4517
 4518                    let point = Point::new(row, 0);
 4519                    let boundary = map.next_line_boundary(point).1;
 4520                    let clipped = map.clip_point(boundary, Bias::Left);
 4521
 4522                    (clipped, SelectionGoal::None)
 4523                });
 4524            });
 4525
 4526            let mut indent_edits = Vec::new();
 4527            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4528            for row in rows {
 4529                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4530                for (row, indent) in indents {
 4531                    if indent.len == 0 {
 4532                        continue;
 4533                    }
 4534
 4535                    let text = match indent.kind {
 4536                        IndentKind::Space => " ".repeat(indent.len as usize),
 4537                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4538                    };
 4539                    let point = Point::new(row.0, 0);
 4540                    indent_edits.push((point..point, text));
 4541                }
 4542            }
 4543            editor.edit(indent_edits, cx);
 4544        });
 4545    }
 4546
 4547    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4548        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4549            original_indent_columns: Vec::new(),
 4550        });
 4551        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4552    }
 4553
 4554    fn insert_with_autoindent_mode(
 4555        &mut self,
 4556        text: &str,
 4557        autoindent_mode: Option<AutoindentMode>,
 4558        window: &mut Window,
 4559        cx: &mut Context<Self>,
 4560    ) {
 4561        if self.read_only(cx) {
 4562            return;
 4563        }
 4564
 4565        let text: Arc<str> = text.into();
 4566        self.transact(window, cx, |this, window, cx| {
 4567            let old_selections = this.selections.all_adjusted(cx);
 4568            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4569                let anchors = {
 4570                    let snapshot = buffer.read(cx);
 4571                    old_selections
 4572                        .iter()
 4573                        .map(|s| {
 4574                            let anchor = snapshot.anchor_after(s.head());
 4575                            s.map(|_| anchor)
 4576                        })
 4577                        .collect::<Vec<_>>()
 4578                };
 4579                buffer.edit(
 4580                    old_selections
 4581                        .iter()
 4582                        .map(|s| (s.start..s.end, text.clone())),
 4583                    autoindent_mode,
 4584                    cx,
 4585                );
 4586                anchors
 4587            });
 4588
 4589            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4590                s.select_anchors(selection_anchors);
 4591            });
 4592
 4593            cx.notify();
 4594        });
 4595    }
 4596
 4597    fn trigger_completion_on_input(
 4598        &mut self,
 4599        text: &str,
 4600        trigger_in_words: bool,
 4601        window: &mut Window,
 4602        cx: &mut Context<Self>,
 4603    ) {
 4604        let completions_source = self
 4605            .context_menu
 4606            .borrow()
 4607            .as_ref()
 4608            .and_then(|menu| match menu {
 4609                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4610                CodeContextMenu::CodeActions(_) => None,
 4611            });
 4612
 4613        match completions_source {
 4614            Some(CompletionsMenuSource::Words) => {
 4615                self.show_word_completions(&ShowWordCompletions, window, cx)
 4616            }
 4617            Some(CompletionsMenuSource::Normal)
 4618            | Some(CompletionsMenuSource::SnippetChoices)
 4619            | None
 4620                if self.is_completion_trigger(
 4621                    text,
 4622                    trigger_in_words,
 4623                    completions_source.is_some(),
 4624                    cx,
 4625                ) =>
 4626            {
 4627                self.show_completions(
 4628                    &ShowCompletions {
 4629                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4630                    },
 4631                    window,
 4632                    cx,
 4633                )
 4634            }
 4635            _ => {
 4636                self.hide_context_menu(window, cx);
 4637            }
 4638        }
 4639    }
 4640
 4641    fn is_completion_trigger(
 4642        &self,
 4643        text: &str,
 4644        trigger_in_words: bool,
 4645        menu_is_open: bool,
 4646        cx: &mut Context<Self>,
 4647    ) -> bool {
 4648        let position = self.selections.newest_anchor().head();
 4649        let multibuffer = self.buffer.read(cx);
 4650        let Some(buffer) = position
 4651            .buffer_id
 4652            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4653        else {
 4654            return false;
 4655        };
 4656
 4657        if let Some(completion_provider) = &self.completion_provider {
 4658            completion_provider.is_completion_trigger(
 4659                &buffer,
 4660                position.text_anchor,
 4661                text,
 4662                trigger_in_words,
 4663                menu_is_open,
 4664                cx,
 4665            )
 4666        } else {
 4667            false
 4668        }
 4669    }
 4670
 4671    /// If any empty selections is touching the start of its innermost containing autoclose
 4672    /// region, expand it to select the brackets.
 4673    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4674        let selections = self.selections.all::<usize>(cx);
 4675        let buffer = self.buffer.read(cx).read(cx);
 4676        let new_selections = self
 4677            .selections_with_autoclose_regions(selections, &buffer)
 4678            .map(|(mut selection, region)| {
 4679                if !selection.is_empty() {
 4680                    return selection;
 4681                }
 4682
 4683                if let Some(region) = region {
 4684                    let mut range = region.range.to_offset(&buffer);
 4685                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4686                        range.start -= region.pair.start.len();
 4687                        if buffer.contains_str_at(range.start, &region.pair.start)
 4688                            && buffer.contains_str_at(range.end, &region.pair.end)
 4689                        {
 4690                            range.end += region.pair.end.len();
 4691                            selection.start = range.start;
 4692                            selection.end = range.end;
 4693
 4694                            return selection;
 4695                        }
 4696                    }
 4697                }
 4698
 4699                let always_treat_brackets_as_autoclosed = buffer
 4700                    .language_settings_at(selection.start, cx)
 4701                    .always_treat_brackets_as_autoclosed;
 4702
 4703                if !always_treat_brackets_as_autoclosed {
 4704                    return selection;
 4705                }
 4706
 4707                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4708                    for (pair, enabled) in scope.brackets() {
 4709                        if !enabled || !pair.close {
 4710                            continue;
 4711                        }
 4712
 4713                        if buffer.contains_str_at(selection.start, &pair.end) {
 4714                            let pair_start_len = pair.start.len();
 4715                            if buffer.contains_str_at(
 4716                                selection.start.saturating_sub(pair_start_len),
 4717                                &pair.start,
 4718                            ) {
 4719                                selection.start -= pair_start_len;
 4720                                selection.end += pair.end.len();
 4721
 4722                                return selection;
 4723                            }
 4724                        }
 4725                    }
 4726                }
 4727
 4728                selection
 4729            })
 4730            .collect();
 4731
 4732        drop(buffer);
 4733        self.change_selections(None, window, cx, |selections| {
 4734            selections.select(new_selections)
 4735        });
 4736    }
 4737
 4738    /// Iterate the given selections, and for each one, find the smallest surrounding
 4739    /// autoclose region. This uses the ordering of the selections and the autoclose
 4740    /// regions to avoid repeated comparisons.
 4741    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4742        &'a self,
 4743        selections: impl IntoIterator<Item = Selection<D>>,
 4744        buffer: &'a MultiBufferSnapshot,
 4745    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4746        let mut i = 0;
 4747        let mut regions = self.autoclose_regions.as_slice();
 4748        selections.into_iter().map(move |selection| {
 4749            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4750
 4751            let mut enclosing = None;
 4752            while let Some(pair_state) = regions.get(i) {
 4753                if pair_state.range.end.to_offset(buffer) < range.start {
 4754                    regions = &regions[i + 1..];
 4755                    i = 0;
 4756                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4757                    break;
 4758                } else {
 4759                    if pair_state.selection_id == selection.id {
 4760                        enclosing = Some(pair_state);
 4761                    }
 4762                    i += 1;
 4763                }
 4764            }
 4765
 4766            (selection, enclosing)
 4767        })
 4768    }
 4769
 4770    /// Remove any autoclose regions that no longer contain their selection.
 4771    fn invalidate_autoclose_regions(
 4772        &mut self,
 4773        mut selections: &[Selection<Anchor>],
 4774        buffer: &MultiBufferSnapshot,
 4775    ) {
 4776        self.autoclose_regions.retain(|state| {
 4777            let mut i = 0;
 4778            while let Some(selection) = selections.get(i) {
 4779                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4780                    selections = &selections[1..];
 4781                    continue;
 4782                }
 4783                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4784                    break;
 4785                }
 4786                if selection.id == state.selection_id {
 4787                    return true;
 4788                } else {
 4789                    i += 1;
 4790                }
 4791            }
 4792            false
 4793        });
 4794    }
 4795
 4796    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4797        let offset = position.to_offset(buffer);
 4798        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4799        if offset > word_range.start && kind == Some(CharKind::Word) {
 4800            Some(
 4801                buffer
 4802                    .text_for_range(word_range.start..offset)
 4803                    .collect::<String>(),
 4804            )
 4805        } else {
 4806            None
 4807        }
 4808    }
 4809
 4810    pub fn toggle_inline_values(
 4811        &mut self,
 4812        _: &ToggleInlineValues,
 4813        _: &mut Window,
 4814        cx: &mut Context<Self>,
 4815    ) {
 4816        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4817
 4818        self.refresh_inline_values(cx);
 4819    }
 4820
 4821    pub fn toggle_inlay_hints(
 4822        &mut self,
 4823        _: &ToggleInlayHints,
 4824        _: &mut Window,
 4825        cx: &mut Context<Self>,
 4826    ) {
 4827        self.refresh_inlay_hints(
 4828            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4829            cx,
 4830        );
 4831    }
 4832
 4833    pub fn inlay_hints_enabled(&self) -> bool {
 4834        self.inlay_hint_cache.enabled
 4835    }
 4836
 4837    pub fn inline_values_enabled(&self) -> bool {
 4838        self.inline_value_cache.enabled
 4839    }
 4840
 4841    #[cfg(any(test, feature = "test-support"))]
 4842    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4843        self.display_map
 4844            .read(cx)
 4845            .current_inlays()
 4846            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4847            .cloned()
 4848            .collect()
 4849    }
 4850
 4851    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4852        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4853            return;
 4854        }
 4855
 4856        let reason_description = reason.description();
 4857        let ignore_debounce = matches!(
 4858            reason,
 4859            InlayHintRefreshReason::SettingsChange(_)
 4860                | InlayHintRefreshReason::Toggle(_)
 4861                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4862                | InlayHintRefreshReason::ModifiersChanged(_)
 4863        );
 4864        let (invalidate_cache, required_languages) = match reason {
 4865            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4866                match self.inlay_hint_cache.modifiers_override(enabled) {
 4867                    Some(enabled) => {
 4868                        if enabled {
 4869                            (InvalidationStrategy::RefreshRequested, None)
 4870                        } else {
 4871                            self.splice_inlays(
 4872                                &self
 4873                                    .visible_inlay_hints(cx)
 4874                                    .iter()
 4875                                    .map(|inlay| inlay.id)
 4876                                    .collect::<Vec<InlayId>>(),
 4877                                Vec::new(),
 4878                                cx,
 4879                            );
 4880                            return;
 4881                        }
 4882                    }
 4883                    None => return,
 4884                }
 4885            }
 4886            InlayHintRefreshReason::Toggle(enabled) => {
 4887                if self.inlay_hint_cache.toggle(enabled) {
 4888                    if enabled {
 4889                        (InvalidationStrategy::RefreshRequested, None)
 4890                    } else {
 4891                        self.splice_inlays(
 4892                            &self
 4893                                .visible_inlay_hints(cx)
 4894                                .iter()
 4895                                .map(|inlay| inlay.id)
 4896                                .collect::<Vec<InlayId>>(),
 4897                            Vec::new(),
 4898                            cx,
 4899                        );
 4900                        return;
 4901                    }
 4902                } else {
 4903                    return;
 4904                }
 4905            }
 4906            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4907                match self.inlay_hint_cache.update_settings(
 4908                    &self.buffer,
 4909                    new_settings,
 4910                    self.visible_inlay_hints(cx),
 4911                    cx,
 4912                ) {
 4913                    ControlFlow::Break(Some(InlaySplice {
 4914                        to_remove,
 4915                        to_insert,
 4916                    })) => {
 4917                        self.splice_inlays(&to_remove, to_insert, cx);
 4918                        return;
 4919                    }
 4920                    ControlFlow::Break(None) => return,
 4921                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4922                }
 4923            }
 4924            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4925                if let Some(InlaySplice {
 4926                    to_remove,
 4927                    to_insert,
 4928                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4929                {
 4930                    self.splice_inlays(&to_remove, to_insert, cx);
 4931                }
 4932                self.display_map.update(cx, |display_map, _| {
 4933                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4934                });
 4935                return;
 4936            }
 4937            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4938            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4939                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4940            }
 4941            InlayHintRefreshReason::RefreshRequested => {
 4942                (InvalidationStrategy::RefreshRequested, None)
 4943            }
 4944        };
 4945
 4946        if let Some(InlaySplice {
 4947            to_remove,
 4948            to_insert,
 4949        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4950            reason_description,
 4951            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4952            invalidate_cache,
 4953            ignore_debounce,
 4954            cx,
 4955        ) {
 4956            self.splice_inlays(&to_remove, to_insert, cx);
 4957        }
 4958    }
 4959
 4960    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4961        self.display_map
 4962            .read(cx)
 4963            .current_inlays()
 4964            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4965            .cloned()
 4966            .collect()
 4967    }
 4968
 4969    pub fn excerpts_for_inlay_hints_query(
 4970        &self,
 4971        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4972        cx: &mut Context<Editor>,
 4973    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4974        let Some(project) = self.project.as_ref() else {
 4975            return HashMap::default();
 4976        };
 4977        let project = project.read(cx);
 4978        let multi_buffer = self.buffer().read(cx);
 4979        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4980        let multi_buffer_visible_start = self
 4981            .scroll_manager
 4982            .anchor()
 4983            .anchor
 4984            .to_point(&multi_buffer_snapshot);
 4985        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4986            multi_buffer_visible_start
 4987                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4988            Bias::Left,
 4989        );
 4990        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4991        multi_buffer_snapshot
 4992            .range_to_buffer_ranges(multi_buffer_visible_range)
 4993            .into_iter()
 4994            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4995            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4996                let buffer_file = project::File::from_dyn(buffer.file())?;
 4997                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4998                let worktree_entry = buffer_worktree
 4999                    .read(cx)
 5000                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5001                if worktree_entry.is_ignored {
 5002                    return None;
 5003                }
 5004
 5005                let language = buffer.language()?;
 5006                if let Some(restrict_to_languages) = restrict_to_languages {
 5007                    if !restrict_to_languages.contains(language) {
 5008                        return None;
 5009                    }
 5010                }
 5011                Some((
 5012                    excerpt_id,
 5013                    (
 5014                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5015                        buffer.version().clone(),
 5016                        excerpt_visible_range,
 5017                    ),
 5018                ))
 5019            })
 5020            .collect()
 5021    }
 5022
 5023    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5024        TextLayoutDetails {
 5025            text_system: window.text_system().clone(),
 5026            editor_style: self.style.clone().unwrap(),
 5027            rem_size: window.rem_size(),
 5028            scroll_anchor: self.scroll_manager.anchor(),
 5029            visible_rows: self.visible_line_count(),
 5030            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5031        }
 5032    }
 5033
 5034    pub fn splice_inlays(
 5035        &self,
 5036        to_remove: &[InlayId],
 5037        to_insert: Vec<Inlay>,
 5038        cx: &mut Context<Self>,
 5039    ) {
 5040        self.display_map.update(cx, |display_map, cx| {
 5041            display_map.splice_inlays(to_remove, to_insert, cx)
 5042        });
 5043        cx.notify();
 5044    }
 5045
 5046    fn trigger_on_type_formatting(
 5047        &self,
 5048        input: String,
 5049        window: &mut Window,
 5050        cx: &mut Context<Self>,
 5051    ) -> Option<Task<Result<()>>> {
 5052        if input.len() != 1 {
 5053            return None;
 5054        }
 5055
 5056        let project = self.project.as_ref()?;
 5057        let position = self.selections.newest_anchor().head();
 5058        let (buffer, buffer_position) = self
 5059            .buffer
 5060            .read(cx)
 5061            .text_anchor_for_position(position, cx)?;
 5062
 5063        let settings = language_settings::language_settings(
 5064            buffer
 5065                .read(cx)
 5066                .language_at(buffer_position)
 5067                .map(|l| l.name()),
 5068            buffer.read(cx).file(),
 5069            cx,
 5070        );
 5071        if !settings.use_on_type_format {
 5072            return None;
 5073        }
 5074
 5075        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5076        // hence we do LSP request & edit on host side only — add formats to host's history.
 5077        let push_to_lsp_host_history = true;
 5078        // If this is not the host, append its history with new edits.
 5079        let push_to_client_history = project.read(cx).is_via_collab();
 5080
 5081        let on_type_formatting = project.update(cx, |project, cx| {
 5082            project.on_type_format(
 5083                buffer.clone(),
 5084                buffer_position,
 5085                input,
 5086                push_to_lsp_host_history,
 5087                cx,
 5088            )
 5089        });
 5090        Some(cx.spawn_in(window, async move |editor, cx| {
 5091            if let Some(transaction) = on_type_formatting.await? {
 5092                if push_to_client_history {
 5093                    buffer
 5094                        .update(cx, |buffer, _| {
 5095                            buffer.push_transaction(transaction, Instant::now());
 5096                            buffer.finalize_last_transaction();
 5097                        })
 5098                        .ok();
 5099                }
 5100                editor.update(cx, |editor, cx| {
 5101                    editor.refresh_document_highlights(cx);
 5102                })?;
 5103            }
 5104            Ok(())
 5105        }))
 5106    }
 5107
 5108    pub fn show_word_completions(
 5109        &mut self,
 5110        _: &ShowWordCompletions,
 5111        window: &mut Window,
 5112        cx: &mut Context<Self>,
 5113    ) {
 5114        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5115    }
 5116
 5117    pub fn show_completions(
 5118        &mut self,
 5119        options: &ShowCompletions,
 5120        window: &mut Window,
 5121        cx: &mut Context<Self>,
 5122    ) {
 5123        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5124    }
 5125
 5126    fn open_or_update_completions_menu(
 5127        &mut self,
 5128        requested_source: Option<CompletionsMenuSource>,
 5129        trigger: Option<&str>,
 5130        window: &mut Window,
 5131        cx: &mut Context<Self>,
 5132    ) {
 5133        if self.pending_rename.is_some() {
 5134            return;
 5135        }
 5136
 5137        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5138
 5139        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5140        // inserted and selected. To handle that case, the start of the selection is used so that
 5141        // the menu starts with all choices.
 5142        let position = self
 5143            .selections
 5144            .newest_anchor()
 5145            .start
 5146            .bias_right(&multibuffer_snapshot);
 5147        if position.diff_base_anchor.is_some() {
 5148            return;
 5149        }
 5150        let (buffer, buffer_position) =
 5151            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5152                output
 5153            } else {
 5154                return;
 5155            };
 5156        let buffer_snapshot = buffer.read(cx).snapshot();
 5157
 5158        let query: Option<Arc<String>> =
 5159            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5160
 5161        drop(multibuffer_snapshot);
 5162
 5163        let provider = match requested_source {
 5164            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5165            Some(CompletionsMenuSource::Words) => None,
 5166            Some(CompletionsMenuSource::SnippetChoices) => {
 5167                log::error!("bug: SnippetChoices requested_source is not handled");
 5168                None
 5169            }
 5170        };
 5171
 5172        let sort_completions = provider
 5173            .as_ref()
 5174            .map_or(false, |provider| provider.sort_completions());
 5175
 5176        let filter_completions = provider
 5177            .as_ref()
 5178            .map_or(true, |provider| provider.filter_completions());
 5179
 5180        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5181            if filter_completions {
 5182                menu.filter(query.clone(), provider.clone(), window, cx);
 5183            }
 5184            // When `is_incomplete` is false, no need to re-query completions when the current query
 5185            // is a suffix of the initial query.
 5186            if !menu.is_incomplete {
 5187                // If the new query is a suffix of the old query (typing more characters) and
 5188                // the previous result was complete, the existing completions can be filtered.
 5189                //
 5190                // Note that this is always true for snippet completions.
 5191                let query_matches = match (&menu.initial_query, &query) {
 5192                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5193                    (None, _) => true,
 5194                    _ => false,
 5195                };
 5196                if query_matches {
 5197                    let position_matches = if menu.initial_position == position {
 5198                        true
 5199                    } else {
 5200                        let snapshot = self.buffer.read(cx).read(cx);
 5201                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5202                    };
 5203                    if position_matches {
 5204                        return;
 5205                    }
 5206                }
 5207            }
 5208        };
 5209
 5210        let trigger_kind = match trigger {
 5211            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5212                CompletionTriggerKind::TRIGGER_CHARACTER
 5213            }
 5214            _ => CompletionTriggerKind::INVOKED,
 5215        };
 5216        let completion_context = CompletionContext {
 5217            trigger_character: trigger.and_then(|trigger| {
 5218                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5219                    Some(String::from(trigger))
 5220                } else {
 5221                    None
 5222                }
 5223            }),
 5224            trigger_kind,
 5225        };
 5226
 5227        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5228            buffer_snapshot.surrounding_word(buffer_position)
 5229        {
 5230            let word_to_exclude = buffer_snapshot
 5231                .text_for_range(word_range.clone())
 5232                .collect::<String>();
 5233            (
 5234                buffer_snapshot.anchor_before(word_range.start)
 5235                    ..buffer_snapshot.anchor_after(buffer_position),
 5236                Some(word_to_exclude),
 5237            )
 5238        } else {
 5239            (buffer_position..buffer_position, None)
 5240        };
 5241
 5242        let language = buffer_snapshot
 5243            .language_at(buffer_position)
 5244            .map(|language| language.name());
 5245
 5246        let completion_settings =
 5247            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5248
 5249        let show_completion_documentation = buffer_snapshot
 5250            .settings_at(buffer_position, cx)
 5251            .show_completion_documentation;
 5252
 5253        // The document can be large, so stay in reasonable bounds when searching for words,
 5254        // otherwise completion pop-up might be slow to appear.
 5255        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5256        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5257        let min_word_search = buffer_snapshot.clip_point(
 5258            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5259            Bias::Left,
 5260        );
 5261        let max_word_search = buffer_snapshot.clip_point(
 5262            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5263            Bias::Right,
 5264        );
 5265        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5266            ..buffer_snapshot.point_to_offset(max_word_search);
 5267
 5268        let skip_digits = query
 5269            .as_ref()
 5270            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5271
 5272        let (mut words, provider_responses) = match &provider {
 5273            Some(provider) => {
 5274                let provider_responses = provider.completions(
 5275                    position.excerpt_id,
 5276                    &buffer,
 5277                    buffer_position,
 5278                    completion_context,
 5279                    window,
 5280                    cx,
 5281                );
 5282
 5283                let words = match completion_settings.words {
 5284                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5285                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5286                        .background_spawn(async move {
 5287                            buffer_snapshot.words_in_range(WordsQuery {
 5288                                fuzzy_contents: None,
 5289                                range: word_search_range,
 5290                                skip_digits,
 5291                            })
 5292                        }),
 5293                };
 5294
 5295                (words, provider_responses)
 5296            }
 5297            None => (
 5298                cx.background_spawn(async move {
 5299                    buffer_snapshot.words_in_range(WordsQuery {
 5300                        fuzzy_contents: None,
 5301                        range: word_search_range,
 5302                        skip_digits,
 5303                    })
 5304                }),
 5305                Task::ready(Ok(Vec::new())),
 5306            ),
 5307        };
 5308
 5309        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5310
 5311        let id = post_inc(&mut self.next_completion_id);
 5312        let task = cx.spawn_in(window, async move |editor, cx| {
 5313            let Ok(()) = editor.update(cx, |this, _| {
 5314                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5315            }) else {
 5316                return;
 5317            };
 5318
 5319            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5320            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5321            let mut completions = Vec::new();
 5322            let mut is_incomplete = false;
 5323            if let Some(provider_responses) = provider_responses.await.log_err() {
 5324                if !provider_responses.is_empty() {
 5325                    for response in provider_responses {
 5326                        completions.extend(response.completions);
 5327                        is_incomplete = is_incomplete || response.is_incomplete;
 5328                    }
 5329                    if completion_settings.words == WordsCompletionMode::Fallback {
 5330                        words = Task::ready(BTreeMap::default());
 5331                    }
 5332                }
 5333            }
 5334
 5335            let mut words = words.await;
 5336            if let Some(word_to_exclude) = &word_to_exclude {
 5337                words.remove(word_to_exclude);
 5338            }
 5339            for lsp_completion in &completions {
 5340                words.remove(&lsp_completion.new_text);
 5341            }
 5342            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5343                replace_range: word_replace_range.clone(),
 5344                new_text: word.clone(),
 5345                label: CodeLabel::plain(word, None),
 5346                icon_path: None,
 5347                documentation: None,
 5348                source: CompletionSource::BufferWord {
 5349                    word_range,
 5350                    resolved: false,
 5351                },
 5352                insert_text_mode: Some(InsertTextMode::AS_IS),
 5353                confirm: None,
 5354            }));
 5355
 5356            let menu = if completions.is_empty() {
 5357                None
 5358            } else {
 5359                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5360                    let languages = editor
 5361                        .workspace
 5362                        .as_ref()
 5363                        .and_then(|(workspace, _)| workspace.upgrade())
 5364                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5365                    let menu = CompletionsMenu::new(
 5366                        id,
 5367                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5368                        sort_completions,
 5369                        show_completion_documentation,
 5370                        position,
 5371                        query.clone(),
 5372                        is_incomplete,
 5373                        buffer.clone(),
 5374                        completions.into(),
 5375                        snippet_sort_order,
 5376                        languages,
 5377                        language,
 5378                        cx,
 5379                    );
 5380
 5381                    let query = if filter_completions { query } else { None };
 5382                    let matches_task = if let Some(query) = query {
 5383                        menu.do_async_filtering(query, cx)
 5384                    } else {
 5385                        Task::ready(menu.unfiltered_matches())
 5386                    };
 5387                    (menu, matches_task)
 5388                }) else {
 5389                    return;
 5390                };
 5391
 5392                let matches = matches_task.await;
 5393
 5394                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5395                    // Newer menu already set, so exit.
 5396                    match editor.context_menu.borrow().as_ref() {
 5397                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5398                            if prev_menu.id > id {
 5399                                return;
 5400                            }
 5401                        }
 5402                        _ => {}
 5403                    };
 5404
 5405                    // Only valid to take prev_menu because it the new menu is immediately set
 5406                    // below, or the menu is hidden.
 5407                    match editor.context_menu.borrow_mut().take() {
 5408                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5409                            let position_matches =
 5410                                if prev_menu.initial_position == menu.initial_position {
 5411                                    true
 5412                                } else {
 5413                                    let snapshot = editor.buffer.read(cx).read(cx);
 5414                                    prev_menu.initial_position.to_offset(&snapshot)
 5415                                        == menu.initial_position.to_offset(&snapshot)
 5416                                };
 5417                            if position_matches {
 5418                                // Preserve markdown cache before `set_filter_results` because it will
 5419                                // try to populate the documentation cache.
 5420                                menu.preserve_markdown_cache(prev_menu);
 5421                            }
 5422                        }
 5423                        _ => {}
 5424                    };
 5425
 5426                    menu.set_filter_results(matches, provider, window, cx);
 5427                }) else {
 5428                    return;
 5429                };
 5430
 5431                menu.visible().then_some(menu)
 5432            };
 5433
 5434            editor
 5435                .update_in(cx, |editor, window, cx| {
 5436                    if editor.focus_handle.is_focused(window) {
 5437                        if let Some(menu) = menu {
 5438                            *editor.context_menu.borrow_mut() =
 5439                                Some(CodeContextMenu::Completions(menu));
 5440
 5441                            crate::hover_popover::hide_hover(editor, cx);
 5442                            if editor.show_edit_predictions_in_menu() {
 5443                                editor.update_visible_inline_completion(window, cx);
 5444                            } else {
 5445                                editor.discard_inline_completion(false, cx);
 5446                            }
 5447
 5448                            cx.notify();
 5449                            return;
 5450                        }
 5451                    }
 5452
 5453                    if editor.completion_tasks.len() <= 1 {
 5454                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5455                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5456                        // If it was already hidden and we don't show inline completions in the menu, we should
 5457                        // also show the inline-completion when available.
 5458                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5459                            editor.update_visible_inline_completion(window, cx);
 5460                        }
 5461                    }
 5462                })
 5463                .ok();
 5464        });
 5465
 5466        self.completion_tasks.push((id, task));
 5467    }
 5468
 5469    #[cfg(feature = "test-support")]
 5470    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5471        let menu = self.context_menu.borrow();
 5472        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5473            let completions = menu.completions.borrow();
 5474            Some(completions.to_vec())
 5475        } else {
 5476            None
 5477        }
 5478    }
 5479
 5480    pub fn with_completions_menu_matching_id<R>(
 5481        &self,
 5482        id: CompletionId,
 5483        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5484    ) -> R {
 5485        let mut context_menu = self.context_menu.borrow_mut();
 5486        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5487            return f(None);
 5488        };
 5489        if completions_menu.id != id {
 5490            return f(None);
 5491        }
 5492        f(Some(completions_menu))
 5493    }
 5494
 5495    pub fn confirm_completion(
 5496        &mut self,
 5497        action: &ConfirmCompletion,
 5498        window: &mut Window,
 5499        cx: &mut Context<Self>,
 5500    ) -> Option<Task<Result<()>>> {
 5501        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5502        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5503    }
 5504
 5505    pub fn confirm_completion_insert(
 5506        &mut self,
 5507        _: &ConfirmCompletionInsert,
 5508        window: &mut Window,
 5509        cx: &mut Context<Self>,
 5510    ) -> Option<Task<Result<()>>> {
 5511        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5512        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5513    }
 5514
 5515    pub fn confirm_completion_replace(
 5516        &mut self,
 5517        _: &ConfirmCompletionReplace,
 5518        window: &mut Window,
 5519        cx: &mut Context<Self>,
 5520    ) -> Option<Task<Result<()>>> {
 5521        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5522        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5523    }
 5524
 5525    pub fn compose_completion(
 5526        &mut self,
 5527        action: &ComposeCompletion,
 5528        window: &mut Window,
 5529        cx: &mut Context<Self>,
 5530    ) -> Option<Task<Result<()>>> {
 5531        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5532        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5533    }
 5534
 5535    fn do_completion(
 5536        &mut self,
 5537        item_ix: Option<usize>,
 5538        intent: CompletionIntent,
 5539        window: &mut Window,
 5540        cx: &mut Context<Editor>,
 5541    ) -> Option<Task<Result<()>>> {
 5542        use language::ToOffset as _;
 5543
 5544        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5545        else {
 5546            return None;
 5547        };
 5548
 5549        let candidate_id = {
 5550            let entries = completions_menu.entries.borrow();
 5551            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5552            if self.show_edit_predictions_in_menu() {
 5553                self.discard_inline_completion(true, cx);
 5554            }
 5555            mat.candidate_id
 5556        };
 5557
 5558        let completion = completions_menu
 5559            .completions
 5560            .borrow()
 5561            .get(candidate_id)?
 5562            .clone();
 5563        cx.stop_propagation();
 5564
 5565        let buffer_handle = completions_menu.buffer.clone();
 5566
 5567        let CompletionEdit {
 5568            new_text,
 5569            snippet,
 5570            replace_range,
 5571        } = process_completion_for_edit(
 5572            &completion,
 5573            intent,
 5574            &buffer_handle,
 5575            &completions_menu.initial_position.text_anchor,
 5576            cx,
 5577        );
 5578
 5579        let buffer = buffer_handle.read(cx);
 5580        let snapshot = self.buffer.read(cx).snapshot(cx);
 5581        let newest_anchor = self.selections.newest_anchor();
 5582        let replace_range_multibuffer = {
 5583            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5584            let multibuffer_anchor = snapshot
 5585                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5586                .unwrap()
 5587                ..snapshot
 5588                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5589                    .unwrap();
 5590            multibuffer_anchor.start.to_offset(&snapshot)
 5591                ..multibuffer_anchor.end.to_offset(&snapshot)
 5592        };
 5593        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5594            return None;
 5595        }
 5596
 5597        let old_text = buffer
 5598            .text_for_range(replace_range.clone())
 5599            .collect::<String>();
 5600        let lookbehind = newest_anchor
 5601            .start
 5602            .text_anchor
 5603            .to_offset(buffer)
 5604            .saturating_sub(replace_range.start);
 5605        let lookahead = replace_range
 5606            .end
 5607            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5608        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5609        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5610
 5611        let selections = self.selections.all::<usize>(cx);
 5612        let mut ranges = Vec::new();
 5613        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5614
 5615        for selection in &selections {
 5616            let range = if selection.id == newest_anchor.id {
 5617                replace_range_multibuffer.clone()
 5618            } else {
 5619                let mut range = selection.range();
 5620
 5621                // if prefix is present, don't duplicate it
 5622                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5623                    range.start = range.start.saturating_sub(lookbehind);
 5624
 5625                    // if suffix is also present, mimic the newest cursor and replace it
 5626                    if selection.id != newest_anchor.id
 5627                        && snapshot.contains_str_at(range.end, suffix)
 5628                    {
 5629                        range.end += lookahead;
 5630                    }
 5631                }
 5632                range
 5633            };
 5634
 5635            ranges.push(range.clone());
 5636
 5637            if !self.linked_edit_ranges.is_empty() {
 5638                let start_anchor = snapshot.anchor_before(range.start);
 5639                let end_anchor = snapshot.anchor_after(range.end);
 5640                if let Some(ranges) = self
 5641                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5642                {
 5643                    for (buffer, edits) in ranges {
 5644                        linked_edits
 5645                            .entry(buffer.clone())
 5646                            .or_default()
 5647                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5648                    }
 5649                }
 5650            }
 5651        }
 5652
 5653        let common_prefix_len = old_text
 5654            .chars()
 5655            .zip(new_text.chars())
 5656            .take_while(|(a, b)| a == b)
 5657            .map(|(a, _)| a.len_utf8())
 5658            .sum::<usize>();
 5659
 5660        cx.emit(EditorEvent::InputHandled {
 5661            utf16_range_to_replace: None,
 5662            text: new_text[common_prefix_len..].into(),
 5663        });
 5664
 5665        self.transact(window, cx, |this, window, cx| {
 5666            if let Some(mut snippet) = snippet {
 5667                snippet.text = new_text.to_string();
 5668                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5669            } else {
 5670                this.buffer.update(cx, |buffer, cx| {
 5671                    let auto_indent = match completion.insert_text_mode {
 5672                        Some(InsertTextMode::AS_IS) => None,
 5673                        _ => this.autoindent_mode.clone(),
 5674                    };
 5675                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5676                    buffer.edit(edits, auto_indent, cx);
 5677                });
 5678            }
 5679            for (buffer, edits) in linked_edits {
 5680                buffer.update(cx, |buffer, cx| {
 5681                    let snapshot = buffer.snapshot();
 5682                    let edits = edits
 5683                        .into_iter()
 5684                        .map(|(range, text)| {
 5685                            use text::ToPoint as TP;
 5686                            let end_point = TP::to_point(&range.end, &snapshot);
 5687                            let start_point = TP::to_point(&range.start, &snapshot);
 5688                            (start_point..end_point, text)
 5689                        })
 5690                        .sorted_by_key(|(range, _)| range.start);
 5691                    buffer.edit(edits, None, cx);
 5692                })
 5693            }
 5694
 5695            this.refresh_inline_completion(true, false, window, cx);
 5696        });
 5697
 5698        let show_new_completions_on_confirm = completion
 5699            .confirm
 5700            .as_ref()
 5701            .map_or(false, |confirm| confirm(intent, window, cx));
 5702        if show_new_completions_on_confirm {
 5703            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5704        }
 5705
 5706        let provider = self.completion_provider.as_ref()?;
 5707        drop(completion);
 5708        let apply_edits = provider.apply_additional_edits_for_completion(
 5709            buffer_handle,
 5710            completions_menu.completions.clone(),
 5711            candidate_id,
 5712            true,
 5713            cx,
 5714        );
 5715
 5716        let editor_settings = EditorSettings::get_global(cx);
 5717        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5718            // After the code completion is finished, users often want to know what signatures are needed.
 5719            // so we should automatically call signature_help
 5720            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5721        }
 5722
 5723        Some(cx.foreground_executor().spawn(async move {
 5724            apply_edits.await?;
 5725            Ok(())
 5726        }))
 5727    }
 5728
 5729    pub fn toggle_code_actions(
 5730        &mut self,
 5731        action: &ToggleCodeActions,
 5732        window: &mut Window,
 5733        cx: &mut Context<Self>,
 5734    ) {
 5735        let quick_launch = action.quick_launch;
 5736        let mut context_menu = self.context_menu.borrow_mut();
 5737        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5738            if code_actions.deployed_from == action.deployed_from {
 5739                // Toggle if we're selecting the same one
 5740                *context_menu = None;
 5741                cx.notify();
 5742                return;
 5743            } else {
 5744                // Otherwise, clear it and start a new one
 5745                *context_menu = None;
 5746                cx.notify();
 5747            }
 5748        }
 5749        drop(context_menu);
 5750        let snapshot = self.snapshot(window, cx);
 5751        let deployed_from = action.deployed_from.clone();
 5752        let action = action.clone();
 5753        self.completion_tasks.clear();
 5754        self.discard_inline_completion(false, cx);
 5755
 5756        let multibuffer_point = match &action.deployed_from {
 5757            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5758                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5759            }
 5760            _ => self.selections.newest::<Point>(cx).head(),
 5761        };
 5762        let Some((buffer, buffer_row)) = snapshot
 5763            .buffer_snapshot
 5764            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5765            .and_then(|(buffer_snapshot, range)| {
 5766                self.buffer()
 5767                    .read(cx)
 5768                    .buffer(buffer_snapshot.remote_id())
 5769                    .map(|buffer| (buffer, range.start.row))
 5770            })
 5771        else {
 5772            return;
 5773        };
 5774        let buffer_id = buffer.read(cx).remote_id();
 5775        let tasks = self
 5776            .tasks
 5777            .get(&(buffer_id, buffer_row))
 5778            .map(|t| Arc::new(t.to_owned()));
 5779
 5780        if !self.focus_handle.is_focused(window) {
 5781            return;
 5782        }
 5783        let project = self.project.clone();
 5784
 5785        let code_actions_task = match deployed_from {
 5786            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5787            _ => self.code_actions(buffer_row, window, cx),
 5788        };
 5789
 5790        let runnable_task = match deployed_from {
 5791            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5792            _ => {
 5793                let mut task_context_task = Task::ready(None);
 5794                if let Some(tasks) = &tasks {
 5795                    if let Some(project) = project {
 5796                        task_context_task =
 5797                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5798                    }
 5799                }
 5800
 5801                cx.spawn_in(window, {
 5802                    let buffer = buffer.clone();
 5803                    async move |editor, cx| {
 5804                        let task_context = task_context_task.await;
 5805
 5806                        let resolved_tasks =
 5807                            tasks
 5808                                .zip(task_context.clone())
 5809                                .map(|(tasks, task_context)| ResolvedTasks {
 5810                                    templates: tasks.resolve(&task_context).collect(),
 5811                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5812                                        multibuffer_point.row,
 5813                                        tasks.column,
 5814                                    )),
 5815                                });
 5816                        let debug_scenarios = editor
 5817                            .update(cx, |editor, cx| {
 5818                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5819                            })?
 5820                            .await;
 5821                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5822                    }
 5823                })
 5824            }
 5825        };
 5826
 5827        cx.spawn_in(window, async move |editor, cx| {
 5828            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5829            let code_actions = code_actions_task.await;
 5830            let spawn_straight_away = quick_launch
 5831                && resolved_tasks
 5832                    .as_ref()
 5833                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5834                && code_actions
 5835                    .as_ref()
 5836                    .map_or(true, |actions| actions.is_empty())
 5837                && debug_scenarios.is_empty();
 5838
 5839            editor.update_in(cx, |editor, window, cx| {
 5840                crate::hover_popover::hide_hover(editor, cx);
 5841                *editor.context_menu.borrow_mut() =
 5842                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5843                        buffer,
 5844                        actions: CodeActionContents::new(
 5845                            resolved_tasks,
 5846                            code_actions,
 5847                            debug_scenarios,
 5848                            task_context.unwrap_or_default(),
 5849                        ),
 5850                        selected_item: Default::default(),
 5851                        scroll_handle: UniformListScrollHandle::default(),
 5852                        deployed_from,
 5853                    }));
 5854                if spawn_straight_away {
 5855                    if let Some(task) = editor.confirm_code_action(
 5856                        &ConfirmCodeAction { item_ix: Some(0) },
 5857                        window,
 5858                        cx,
 5859                    ) {
 5860                        cx.notify();
 5861                        return task;
 5862                    }
 5863                }
 5864
 5865                Task::ready(Ok(()))
 5866            })
 5867        })
 5868        .detach_and_log_err(cx);
 5869    }
 5870
 5871    fn debug_scenarios(
 5872        &mut self,
 5873        resolved_tasks: &Option<ResolvedTasks>,
 5874        buffer: &Entity<Buffer>,
 5875        cx: &mut App,
 5876    ) -> Task<Vec<task::DebugScenario>> {
 5877        if cx.has_flag::<DebuggerFeatureFlag>() {
 5878            maybe!({
 5879                let project = self.project.as_ref()?;
 5880                let dap_store = project.read(cx).dap_store();
 5881                let mut scenarios = vec![];
 5882                let resolved_tasks = resolved_tasks.as_ref()?;
 5883                let buffer = buffer.read(cx);
 5884                let language = buffer.language()?;
 5885                let file = buffer.file();
 5886                let debug_adapter = language_settings(language.name().into(), file, cx)
 5887                    .debuggers
 5888                    .first()
 5889                    .map(SharedString::from)
 5890                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5891
 5892                dap_store.update(cx, |dap_store, cx| {
 5893                    for (_, task) in &resolved_tasks.templates {
 5894                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5895                            task.original_task().clone(),
 5896                            debug_adapter.clone().into(),
 5897                            task.display_label().to_owned().into(),
 5898                            cx,
 5899                        );
 5900                        scenarios.push(maybe_scenario);
 5901                    }
 5902                });
 5903                Some(cx.background_spawn(async move {
 5904                    let scenarios = futures::future::join_all(scenarios)
 5905                        .await
 5906                        .into_iter()
 5907                        .flatten()
 5908                        .collect::<Vec<_>>();
 5909                    scenarios
 5910                }))
 5911            })
 5912            .unwrap_or_else(|| Task::ready(vec![]))
 5913        } else {
 5914            Task::ready(vec![])
 5915        }
 5916    }
 5917
 5918    fn code_actions(
 5919        &mut self,
 5920        buffer_row: u32,
 5921        window: &mut Window,
 5922        cx: &mut Context<Self>,
 5923    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5924        let mut task = self.code_actions_task.take();
 5925        cx.spawn_in(window, async move |editor, cx| {
 5926            while let Some(prev_task) = task {
 5927                prev_task.await.log_err();
 5928                task = editor
 5929                    .update(cx, |this, _| this.code_actions_task.take())
 5930                    .ok()?;
 5931            }
 5932
 5933            editor
 5934                .update(cx, |editor, cx| {
 5935                    editor
 5936                        .available_code_actions
 5937                        .clone()
 5938                        .and_then(|(location, code_actions)| {
 5939                            let snapshot = location.buffer.read(cx).snapshot();
 5940                            let point_range = location.range.to_point(&snapshot);
 5941                            let point_range = point_range.start.row..=point_range.end.row;
 5942                            if point_range.contains(&buffer_row) {
 5943                                Some(code_actions)
 5944                            } else {
 5945                                None
 5946                            }
 5947                        })
 5948                })
 5949                .ok()
 5950                .flatten()
 5951        })
 5952    }
 5953
 5954    pub fn confirm_code_action(
 5955        &mut self,
 5956        action: &ConfirmCodeAction,
 5957        window: &mut Window,
 5958        cx: &mut Context<Self>,
 5959    ) -> Option<Task<Result<()>>> {
 5960        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5961
 5962        let actions_menu =
 5963            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5964                menu
 5965            } else {
 5966                return None;
 5967            };
 5968
 5969        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5970        let action = actions_menu.actions.get(action_ix)?;
 5971        let title = action.label();
 5972        let buffer = actions_menu.buffer;
 5973        let workspace = self.workspace()?;
 5974
 5975        match action {
 5976            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5977                workspace.update(cx, |workspace, cx| {
 5978                    workspace.schedule_resolved_task(
 5979                        task_source_kind,
 5980                        resolved_task,
 5981                        false,
 5982                        window,
 5983                        cx,
 5984                    );
 5985
 5986                    Some(Task::ready(Ok(())))
 5987                })
 5988            }
 5989            CodeActionsItem::CodeAction {
 5990                excerpt_id,
 5991                action,
 5992                provider,
 5993            } => {
 5994                let apply_code_action =
 5995                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5996                let workspace = workspace.downgrade();
 5997                Some(cx.spawn_in(window, async move |editor, cx| {
 5998                    let project_transaction = apply_code_action.await?;
 5999                    Self::open_project_transaction(
 6000                        &editor,
 6001                        workspace,
 6002                        project_transaction,
 6003                        title,
 6004                        cx,
 6005                    )
 6006                    .await
 6007                }))
 6008            }
 6009            CodeActionsItem::DebugScenario(scenario) => {
 6010                let context = actions_menu.actions.context.clone();
 6011
 6012                workspace.update(cx, |workspace, cx| {
 6013                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6014                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6015                });
 6016                Some(Task::ready(Ok(())))
 6017            }
 6018        }
 6019    }
 6020
 6021    pub async fn open_project_transaction(
 6022        this: &WeakEntity<Editor>,
 6023        workspace: WeakEntity<Workspace>,
 6024        transaction: ProjectTransaction,
 6025        title: String,
 6026        cx: &mut AsyncWindowContext,
 6027    ) -> Result<()> {
 6028        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6029        cx.update(|_, cx| {
 6030            entries.sort_unstable_by_key(|(buffer, _)| {
 6031                buffer.read(cx).file().map(|f| f.path().clone())
 6032            });
 6033        })?;
 6034
 6035        // If the project transaction's edits are all contained within this editor, then
 6036        // avoid opening a new editor to display them.
 6037
 6038        if let Some((buffer, transaction)) = entries.first() {
 6039            if entries.len() == 1 {
 6040                let excerpt = this.update(cx, |editor, cx| {
 6041                    editor
 6042                        .buffer()
 6043                        .read(cx)
 6044                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6045                })?;
 6046                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6047                    if excerpted_buffer == *buffer {
 6048                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6049                            let excerpt_range = excerpt_range.to_offset(buffer);
 6050                            buffer
 6051                                .edited_ranges_for_transaction::<usize>(transaction)
 6052                                .all(|range| {
 6053                                    excerpt_range.start <= range.start
 6054                                        && excerpt_range.end >= range.end
 6055                                })
 6056                        })?;
 6057
 6058                        if all_edits_within_excerpt {
 6059                            return Ok(());
 6060                        }
 6061                    }
 6062                }
 6063            }
 6064        } else {
 6065            return Ok(());
 6066        }
 6067
 6068        let mut ranges_to_highlight = Vec::new();
 6069        let excerpt_buffer = cx.new(|cx| {
 6070            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6071            for (buffer_handle, transaction) in &entries {
 6072                let edited_ranges = buffer_handle
 6073                    .read(cx)
 6074                    .edited_ranges_for_transaction::<Point>(transaction)
 6075                    .collect::<Vec<_>>();
 6076                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6077                    PathKey::for_buffer(buffer_handle, cx),
 6078                    buffer_handle.clone(),
 6079                    edited_ranges,
 6080                    DEFAULT_MULTIBUFFER_CONTEXT,
 6081                    cx,
 6082                );
 6083
 6084                ranges_to_highlight.extend(ranges);
 6085            }
 6086            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6087            multibuffer
 6088        })?;
 6089
 6090        workspace.update_in(cx, |workspace, window, cx| {
 6091            let project = workspace.project().clone();
 6092            let editor =
 6093                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6094            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6095            editor.update(cx, |editor, cx| {
 6096                editor.highlight_background::<Self>(
 6097                    &ranges_to_highlight,
 6098                    |theme| theme.editor_highlighted_line_background,
 6099                    cx,
 6100                );
 6101            });
 6102        })?;
 6103
 6104        Ok(())
 6105    }
 6106
 6107    pub fn clear_code_action_providers(&mut self) {
 6108        self.code_action_providers.clear();
 6109        self.available_code_actions.take();
 6110    }
 6111
 6112    pub fn add_code_action_provider(
 6113        &mut self,
 6114        provider: Rc<dyn CodeActionProvider>,
 6115        window: &mut Window,
 6116        cx: &mut Context<Self>,
 6117    ) {
 6118        if self
 6119            .code_action_providers
 6120            .iter()
 6121            .any(|existing_provider| existing_provider.id() == provider.id())
 6122        {
 6123            return;
 6124        }
 6125
 6126        self.code_action_providers.push(provider);
 6127        self.refresh_code_actions(window, cx);
 6128    }
 6129
 6130    pub fn remove_code_action_provider(
 6131        &mut self,
 6132        id: Arc<str>,
 6133        window: &mut Window,
 6134        cx: &mut Context<Self>,
 6135    ) {
 6136        self.code_action_providers
 6137            .retain(|provider| provider.id() != id);
 6138        self.refresh_code_actions(window, cx);
 6139    }
 6140
 6141    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6142        !self.code_action_providers.is_empty()
 6143            && EditorSettings::get_global(cx).toolbar.code_actions
 6144    }
 6145
 6146    pub fn has_available_code_actions(&self) -> bool {
 6147        self.available_code_actions
 6148            .as_ref()
 6149            .is_some_and(|(_, actions)| !actions.is_empty())
 6150    }
 6151
 6152    fn render_inline_code_actions(
 6153        &self,
 6154        icon_size: ui::IconSize,
 6155        display_row: DisplayRow,
 6156        is_active: bool,
 6157        cx: &mut Context<Self>,
 6158    ) -> AnyElement {
 6159        let show_tooltip = !self.context_menu_visible();
 6160        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6161            .icon_size(icon_size)
 6162            .shape(ui::IconButtonShape::Square)
 6163            .style(ButtonStyle::Transparent)
 6164            .icon_color(ui::Color::Hidden)
 6165            .toggle_state(is_active)
 6166            .when(show_tooltip, |this| {
 6167                this.tooltip({
 6168                    let focus_handle = self.focus_handle.clone();
 6169                    move |window, cx| {
 6170                        Tooltip::for_action_in(
 6171                            "Toggle Code Actions",
 6172                            &ToggleCodeActions {
 6173                                deployed_from: None,
 6174                                quick_launch: false,
 6175                            },
 6176                            &focus_handle,
 6177                            window,
 6178                            cx,
 6179                        )
 6180                    }
 6181                })
 6182            })
 6183            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6184                window.focus(&editor.focus_handle(cx));
 6185                editor.toggle_code_actions(
 6186                    &crate::actions::ToggleCodeActions {
 6187                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6188                            display_row,
 6189                        )),
 6190                        quick_launch: false,
 6191                    },
 6192                    window,
 6193                    cx,
 6194                );
 6195            }))
 6196            .into_any_element()
 6197    }
 6198
 6199    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6200        &self.context_menu
 6201    }
 6202
 6203    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6204        let newest_selection = self.selections.newest_anchor().clone();
 6205        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6206        let buffer = self.buffer.read(cx);
 6207        if newest_selection.head().diff_base_anchor.is_some() {
 6208            return None;
 6209        }
 6210        let (start_buffer, start) =
 6211            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6212        let (end_buffer, end) =
 6213            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6214        if start_buffer != end_buffer {
 6215            return None;
 6216        }
 6217
 6218        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6219            cx.background_executor()
 6220                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6221                .await;
 6222
 6223            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6224                let providers = this.code_action_providers.clone();
 6225                let tasks = this
 6226                    .code_action_providers
 6227                    .iter()
 6228                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6229                    .collect::<Vec<_>>();
 6230                (providers, tasks)
 6231            })?;
 6232
 6233            let mut actions = Vec::new();
 6234            for (provider, provider_actions) in
 6235                providers.into_iter().zip(future::join_all(tasks).await)
 6236            {
 6237                if let Some(provider_actions) = provider_actions.log_err() {
 6238                    actions.extend(provider_actions.into_iter().map(|action| {
 6239                        AvailableCodeAction {
 6240                            excerpt_id: newest_selection.start.excerpt_id,
 6241                            action,
 6242                            provider: provider.clone(),
 6243                        }
 6244                    }));
 6245                }
 6246            }
 6247
 6248            this.update(cx, |this, cx| {
 6249                this.available_code_actions = if actions.is_empty() {
 6250                    None
 6251                } else {
 6252                    Some((
 6253                        Location {
 6254                            buffer: start_buffer,
 6255                            range: start..end,
 6256                        },
 6257                        actions.into(),
 6258                    ))
 6259                };
 6260                cx.notify();
 6261            })
 6262        }));
 6263        None
 6264    }
 6265
 6266    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6267        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6268            self.show_git_blame_inline = false;
 6269
 6270            self.show_git_blame_inline_delay_task =
 6271                Some(cx.spawn_in(window, async move |this, cx| {
 6272                    cx.background_executor().timer(delay).await;
 6273
 6274                    this.update(cx, |this, cx| {
 6275                        this.show_git_blame_inline = true;
 6276                        cx.notify();
 6277                    })
 6278                    .log_err();
 6279                }));
 6280        }
 6281    }
 6282
 6283    fn show_blame_popover(
 6284        &mut self,
 6285        blame_entry: &BlameEntry,
 6286        position: gpui::Point<Pixels>,
 6287        cx: &mut Context<Self>,
 6288    ) {
 6289        if let Some(state) = &mut self.inline_blame_popover {
 6290            state.hide_task.take();
 6291        } else {
 6292            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6293            let blame_entry = blame_entry.clone();
 6294            let show_task = cx.spawn(async move |editor, cx| {
 6295                cx.background_executor()
 6296                    .timer(std::time::Duration::from_millis(delay))
 6297                    .await;
 6298                editor
 6299                    .update(cx, |editor, cx| {
 6300                        editor.inline_blame_popover_show_task.take();
 6301                        let Some(blame) = editor.blame.as_ref() else {
 6302                            return;
 6303                        };
 6304                        let blame = blame.read(cx);
 6305                        let details = blame.details_for_entry(&blame_entry);
 6306                        let markdown = cx.new(|cx| {
 6307                            Markdown::new(
 6308                                details
 6309                                    .as_ref()
 6310                                    .map(|message| message.message.clone())
 6311                                    .unwrap_or_default(),
 6312                                None,
 6313                                None,
 6314                                cx,
 6315                            )
 6316                        });
 6317                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6318                            position,
 6319                            hide_task: None,
 6320                            popover_bounds: None,
 6321                            popover_state: InlineBlamePopoverState {
 6322                                scroll_handle: ScrollHandle::new(),
 6323                                commit_message: details,
 6324                                markdown,
 6325                            },
 6326                        });
 6327                        cx.notify();
 6328                    })
 6329                    .ok();
 6330            });
 6331            self.inline_blame_popover_show_task = Some(show_task);
 6332        }
 6333    }
 6334
 6335    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6336        self.inline_blame_popover_show_task.take();
 6337        if let Some(state) = &mut self.inline_blame_popover {
 6338            let hide_task = cx.spawn(async move |editor, cx| {
 6339                cx.background_executor()
 6340                    .timer(std::time::Duration::from_millis(100))
 6341                    .await;
 6342                editor
 6343                    .update(cx, |editor, cx| {
 6344                        editor.inline_blame_popover.take();
 6345                        cx.notify();
 6346                    })
 6347                    .ok();
 6348            });
 6349            state.hide_task = Some(hide_task);
 6350        }
 6351    }
 6352
 6353    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6354        if self.pending_rename.is_some() {
 6355            return None;
 6356        }
 6357
 6358        let provider = self.semantics_provider.clone()?;
 6359        let buffer = self.buffer.read(cx);
 6360        let newest_selection = self.selections.newest_anchor().clone();
 6361        let cursor_position = newest_selection.head();
 6362        let (cursor_buffer, cursor_buffer_position) =
 6363            buffer.text_anchor_for_position(cursor_position, cx)?;
 6364        let (tail_buffer, tail_buffer_position) =
 6365            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6366        if cursor_buffer != tail_buffer {
 6367            return None;
 6368        }
 6369
 6370        let snapshot = cursor_buffer.read(cx).snapshot();
 6371        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6372        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6373        if start_word_range != end_word_range {
 6374            self.document_highlights_task.take();
 6375            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6376            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6377            return None;
 6378        }
 6379
 6380        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6381        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6382            cx.background_executor()
 6383                .timer(Duration::from_millis(debounce))
 6384                .await;
 6385
 6386            let highlights = if let Some(highlights) = cx
 6387                .update(|cx| {
 6388                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6389                })
 6390                .ok()
 6391                .flatten()
 6392            {
 6393                highlights.await.log_err()
 6394            } else {
 6395                None
 6396            };
 6397
 6398            if let Some(highlights) = highlights {
 6399                this.update(cx, |this, cx| {
 6400                    if this.pending_rename.is_some() {
 6401                        return;
 6402                    }
 6403
 6404                    let buffer_id = cursor_position.buffer_id;
 6405                    let buffer = this.buffer.read(cx);
 6406                    if !buffer
 6407                        .text_anchor_for_position(cursor_position, cx)
 6408                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6409                    {
 6410                        return;
 6411                    }
 6412
 6413                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6414                    let mut write_ranges = Vec::new();
 6415                    let mut read_ranges = Vec::new();
 6416                    for highlight in highlights {
 6417                        for (excerpt_id, excerpt_range) in
 6418                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6419                        {
 6420                            let start = highlight
 6421                                .range
 6422                                .start
 6423                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6424                            let end = highlight
 6425                                .range
 6426                                .end
 6427                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6428                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6429                                continue;
 6430                            }
 6431
 6432                            let range = Anchor {
 6433                                buffer_id,
 6434                                excerpt_id,
 6435                                text_anchor: start,
 6436                                diff_base_anchor: None,
 6437                            }..Anchor {
 6438                                buffer_id,
 6439                                excerpt_id,
 6440                                text_anchor: end,
 6441                                diff_base_anchor: None,
 6442                            };
 6443                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6444                                write_ranges.push(range);
 6445                            } else {
 6446                                read_ranges.push(range);
 6447                            }
 6448                        }
 6449                    }
 6450
 6451                    this.highlight_background::<DocumentHighlightRead>(
 6452                        &read_ranges,
 6453                        |theme| theme.editor_document_highlight_read_background,
 6454                        cx,
 6455                    );
 6456                    this.highlight_background::<DocumentHighlightWrite>(
 6457                        &write_ranges,
 6458                        |theme| theme.editor_document_highlight_write_background,
 6459                        cx,
 6460                    );
 6461                    cx.notify();
 6462                })
 6463                .log_err();
 6464            }
 6465        }));
 6466        None
 6467    }
 6468
 6469    fn prepare_highlight_query_from_selection(
 6470        &mut self,
 6471        cx: &mut Context<Editor>,
 6472    ) -> Option<(String, Range<Anchor>)> {
 6473        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6474            return None;
 6475        }
 6476        if !EditorSettings::get_global(cx).selection_highlight {
 6477            return None;
 6478        }
 6479        if self.selections.count() != 1 || self.selections.line_mode {
 6480            return None;
 6481        }
 6482        let selection = self.selections.newest::<Point>(cx);
 6483        if selection.is_empty() || selection.start.row != selection.end.row {
 6484            return None;
 6485        }
 6486        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6487        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6488        let query = multi_buffer_snapshot
 6489            .text_for_range(selection_anchor_range.clone())
 6490            .collect::<String>();
 6491        if query.trim().is_empty() {
 6492            return None;
 6493        }
 6494        Some((query, selection_anchor_range))
 6495    }
 6496
 6497    fn update_selection_occurrence_highlights(
 6498        &mut self,
 6499        query_text: String,
 6500        query_range: Range<Anchor>,
 6501        multi_buffer_range_to_query: Range<Point>,
 6502        use_debounce: bool,
 6503        window: &mut Window,
 6504        cx: &mut Context<Editor>,
 6505    ) -> Task<()> {
 6506        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6507        cx.spawn_in(window, async move |editor, cx| {
 6508            if use_debounce {
 6509                cx.background_executor()
 6510                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6511                    .await;
 6512            }
 6513            let match_task = cx.background_spawn(async move {
 6514                let buffer_ranges = multi_buffer_snapshot
 6515                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6516                    .into_iter()
 6517                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6518                let mut match_ranges = Vec::new();
 6519                let Ok(regex) = project::search::SearchQuery::text(
 6520                    query_text.clone(),
 6521                    false,
 6522                    false,
 6523                    false,
 6524                    Default::default(),
 6525                    Default::default(),
 6526                    false,
 6527                    None,
 6528                ) else {
 6529                    return Vec::default();
 6530                };
 6531                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6532                    match_ranges.extend(
 6533                        regex
 6534                            .search(&buffer_snapshot, Some(search_range.clone()))
 6535                            .await
 6536                            .into_iter()
 6537                            .filter_map(|match_range| {
 6538                                let match_start = buffer_snapshot
 6539                                    .anchor_after(search_range.start + match_range.start);
 6540                                let match_end = buffer_snapshot
 6541                                    .anchor_before(search_range.start + match_range.end);
 6542                                let match_anchor_range = Anchor::range_in_buffer(
 6543                                    excerpt_id,
 6544                                    buffer_snapshot.remote_id(),
 6545                                    match_start..match_end,
 6546                                );
 6547                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6548                            }),
 6549                    );
 6550                }
 6551                match_ranges
 6552            });
 6553            let match_ranges = match_task.await;
 6554            editor
 6555                .update_in(cx, |editor, _, cx| {
 6556                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6557                    if !match_ranges.is_empty() {
 6558                        editor.highlight_background::<SelectedTextHighlight>(
 6559                            &match_ranges,
 6560                            |theme| theme.editor_document_highlight_bracket_background,
 6561                            cx,
 6562                        )
 6563                    }
 6564                })
 6565                .log_err();
 6566        })
 6567    }
 6568
 6569    fn refresh_selected_text_highlights(
 6570        &mut self,
 6571        on_buffer_edit: bool,
 6572        window: &mut Window,
 6573        cx: &mut Context<Editor>,
 6574    ) {
 6575        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6576        else {
 6577            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6578            self.quick_selection_highlight_task.take();
 6579            self.debounced_selection_highlight_task.take();
 6580            return;
 6581        };
 6582        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6583        if on_buffer_edit
 6584            || self
 6585                .quick_selection_highlight_task
 6586                .as_ref()
 6587                .map_or(true, |(prev_anchor_range, _)| {
 6588                    prev_anchor_range != &query_range
 6589                })
 6590        {
 6591            let multi_buffer_visible_start = self
 6592                .scroll_manager
 6593                .anchor()
 6594                .anchor
 6595                .to_point(&multi_buffer_snapshot);
 6596            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6597                multi_buffer_visible_start
 6598                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6599                Bias::Left,
 6600            );
 6601            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6602            self.quick_selection_highlight_task = Some((
 6603                query_range.clone(),
 6604                self.update_selection_occurrence_highlights(
 6605                    query_text.clone(),
 6606                    query_range.clone(),
 6607                    multi_buffer_visible_range,
 6608                    false,
 6609                    window,
 6610                    cx,
 6611                ),
 6612            ));
 6613        }
 6614        if on_buffer_edit
 6615            || self
 6616                .debounced_selection_highlight_task
 6617                .as_ref()
 6618                .map_or(true, |(prev_anchor_range, _)| {
 6619                    prev_anchor_range != &query_range
 6620                })
 6621        {
 6622            let multi_buffer_start = multi_buffer_snapshot
 6623                .anchor_before(0)
 6624                .to_point(&multi_buffer_snapshot);
 6625            let multi_buffer_end = multi_buffer_snapshot
 6626                .anchor_after(multi_buffer_snapshot.len())
 6627                .to_point(&multi_buffer_snapshot);
 6628            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6629            self.debounced_selection_highlight_task = Some((
 6630                query_range.clone(),
 6631                self.update_selection_occurrence_highlights(
 6632                    query_text,
 6633                    query_range,
 6634                    multi_buffer_full_range,
 6635                    true,
 6636                    window,
 6637                    cx,
 6638                ),
 6639            ));
 6640        }
 6641    }
 6642
 6643    pub fn refresh_inline_completion(
 6644        &mut self,
 6645        debounce: bool,
 6646        user_requested: bool,
 6647        window: &mut Window,
 6648        cx: &mut Context<Self>,
 6649    ) -> Option<()> {
 6650        let provider = self.edit_prediction_provider()?;
 6651        let cursor = self.selections.newest_anchor().head();
 6652        let (buffer, cursor_buffer_position) =
 6653            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6654
 6655        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6656            self.discard_inline_completion(false, cx);
 6657            return None;
 6658        }
 6659
 6660        if !user_requested
 6661            && (!self.should_show_edit_predictions()
 6662                || !self.is_focused(window)
 6663                || buffer.read(cx).is_empty())
 6664        {
 6665            self.discard_inline_completion(false, cx);
 6666            return None;
 6667        }
 6668
 6669        self.update_visible_inline_completion(window, cx);
 6670        provider.refresh(
 6671            self.project.clone(),
 6672            buffer,
 6673            cursor_buffer_position,
 6674            debounce,
 6675            cx,
 6676        );
 6677        Some(())
 6678    }
 6679
 6680    fn show_edit_predictions_in_menu(&self) -> bool {
 6681        match self.edit_prediction_settings {
 6682            EditPredictionSettings::Disabled => false,
 6683            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6684        }
 6685    }
 6686
 6687    pub fn edit_predictions_enabled(&self) -> bool {
 6688        match self.edit_prediction_settings {
 6689            EditPredictionSettings::Disabled => false,
 6690            EditPredictionSettings::Enabled { .. } => true,
 6691        }
 6692    }
 6693
 6694    fn edit_prediction_requires_modifier(&self) -> bool {
 6695        match self.edit_prediction_settings {
 6696            EditPredictionSettings::Disabled => false,
 6697            EditPredictionSettings::Enabled {
 6698                preview_requires_modifier,
 6699                ..
 6700            } => preview_requires_modifier,
 6701        }
 6702    }
 6703
 6704    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6705        if self.edit_prediction_provider.is_none() {
 6706            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6707        } else {
 6708            let selection = self.selections.newest_anchor();
 6709            let cursor = selection.head();
 6710
 6711            if let Some((buffer, cursor_buffer_position)) =
 6712                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6713            {
 6714                self.edit_prediction_settings =
 6715                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6716            }
 6717        }
 6718    }
 6719
 6720    fn edit_prediction_settings_at_position(
 6721        &self,
 6722        buffer: &Entity<Buffer>,
 6723        buffer_position: language::Anchor,
 6724        cx: &App,
 6725    ) -> EditPredictionSettings {
 6726        if !self.mode.is_full()
 6727            || !self.show_inline_completions_override.unwrap_or(true)
 6728            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6729        {
 6730            return EditPredictionSettings::Disabled;
 6731        }
 6732
 6733        let buffer = buffer.read(cx);
 6734
 6735        let file = buffer.file();
 6736
 6737        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6738            return EditPredictionSettings::Disabled;
 6739        };
 6740
 6741        let by_provider = matches!(
 6742            self.menu_inline_completions_policy,
 6743            MenuInlineCompletionsPolicy::ByProvider
 6744        );
 6745
 6746        let show_in_menu = by_provider
 6747            && self
 6748                .edit_prediction_provider
 6749                .as_ref()
 6750                .map_or(false, |provider| {
 6751                    provider.provider.show_completions_in_menu()
 6752                });
 6753
 6754        let preview_requires_modifier =
 6755            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6756
 6757        EditPredictionSettings::Enabled {
 6758            show_in_menu,
 6759            preview_requires_modifier,
 6760        }
 6761    }
 6762
 6763    fn should_show_edit_predictions(&self) -> bool {
 6764        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6765    }
 6766
 6767    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6768        matches!(
 6769            self.edit_prediction_preview,
 6770            EditPredictionPreview::Active { .. }
 6771        )
 6772    }
 6773
 6774    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6775        let cursor = self.selections.newest_anchor().head();
 6776        if let Some((buffer, cursor_position)) =
 6777            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6778        {
 6779            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6780        } else {
 6781            false
 6782        }
 6783    }
 6784
 6785    pub fn supports_minimap(&self, cx: &App) -> bool {
 6786        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6787    }
 6788
 6789    fn edit_predictions_enabled_in_buffer(
 6790        &self,
 6791        buffer: &Entity<Buffer>,
 6792        buffer_position: language::Anchor,
 6793        cx: &App,
 6794    ) -> bool {
 6795        maybe!({
 6796            if self.read_only(cx) {
 6797                return Some(false);
 6798            }
 6799            let provider = self.edit_prediction_provider()?;
 6800            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6801                return Some(false);
 6802            }
 6803            let buffer = buffer.read(cx);
 6804            let Some(file) = buffer.file() else {
 6805                return Some(true);
 6806            };
 6807            let settings = all_language_settings(Some(file), cx);
 6808            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6809        })
 6810        .unwrap_or(false)
 6811    }
 6812
 6813    fn cycle_inline_completion(
 6814        &mut self,
 6815        direction: Direction,
 6816        window: &mut Window,
 6817        cx: &mut Context<Self>,
 6818    ) -> Option<()> {
 6819        let provider = self.edit_prediction_provider()?;
 6820        let cursor = self.selections.newest_anchor().head();
 6821        let (buffer, cursor_buffer_position) =
 6822            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6823        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6824            return None;
 6825        }
 6826
 6827        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6828        self.update_visible_inline_completion(window, cx);
 6829
 6830        Some(())
 6831    }
 6832
 6833    pub fn show_inline_completion(
 6834        &mut self,
 6835        _: &ShowEditPrediction,
 6836        window: &mut Window,
 6837        cx: &mut Context<Self>,
 6838    ) {
 6839        if !self.has_active_inline_completion() {
 6840            self.refresh_inline_completion(false, true, window, cx);
 6841            return;
 6842        }
 6843
 6844        self.update_visible_inline_completion(window, cx);
 6845    }
 6846
 6847    pub fn display_cursor_names(
 6848        &mut self,
 6849        _: &DisplayCursorNames,
 6850        window: &mut Window,
 6851        cx: &mut Context<Self>,
 6852    ) {
 6853        self.show_cursor_names(window, cx);
 6854    }
 6855
 6856    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6857        self.show_cursor_names = true;
 6858        cx.notify();
 6859        cx.spawn_in(window, async move |this, cx| {
 6860            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6861            this.update(cx, |this, cx| {
 6862                this.show_cursor_names = false;
 6863                cx.notify()
 6864            })
 6865            .ok()
 6866        })
 6867        .detach();
 6868    }
 6869
 6870    pub fn next_edit_prediction(
 6871        &mut self,
 6872        _: &NextEditPrediction,
 6873        window: &mut Window,
 6874        cx: &mut Context<Self>,
 6875    ) {
 6876        if self.has_active_inline_completion() {
 6877            self.cycle_inline_completion(Direction::Next, window, cx);
 6878        } else {
 6879            let is_copilot_disabled = self
 6880                .refresh_inline_completion(false, true, window, cx)
 6881                .is_none();
 6882            if is_copilot_disabled {
 6883                cx.propagate();
 6884            }
 6885        }
 6886    }
 6887
 6888    pub fn previous_edit_prediction(
 6889        &mut self,
 6890        _: &PreviousEditPrediction,
 6891        window: &mut Window,
 6892        cx: &mut Context<Self>,
 6893    ) {
 6894        if self.has_active_inline_completion() {
 6895            self.cycle_inline_completion(Direction::Prev, window, cx);
 6896        } else {
 6897            let is_copilot_disabled = self
 6898                .refresh_inline_completion(false, true, window, cx)
 6899                .is_none();
 6900            if is_copilot_disabled {
 6901                cx.propagate();
 6902            }
 6903        }
 6904    }
 6905
 6906    pub fn accept_edit_prediction(
 6907        &mut self,
 6908        _: &AcceptEditPrediction,
 6909        window: &mut Window,
 6910        cx: &mut Context<Self>,
 6911    ) {
 6912        if self.show_edit_predictions_in_menu() {
 6913            self.hide_context_menu(window, cx);
 6914        }
 6915
 6916        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6917            return;
 6918        };
 6919
 6920        self.report_inline_completion_event(
 6921            active_inline_completion.completion_id.clone(),
 6922            true,
 6923            cx,
 6924        );
 6925
 6926        match &active_inline_completion.completion {
 6927            InlineCompletion::Move { target, .. } => {
 6928                let target = *target;
 6929
 6930                if let Some(position_map) = &self.last_position_map {
 6931                    if position_map
 6932                        .visible_row_range
 6933                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6934                        || !self.edit_prediction_requires_modifier()
 6935                    {
 6936                        self.unfold_ranges(&[target..target], true, false, cx);
 6937                        // Note that this is also done in vim's handler of the Tab action.
 6938                        self.change_selections(
 6939                            Some(Autoscroll::newest()),
 6940                            window,
 6941                            cx,
 6942                            |selections| {
 6943                                selections.select_anchor_ranges([target..target]);
 6944                            },
 6945                        );
 6946                        self.clear_row_highlights::<EditPredictionPreview>();
 6947
 6948                        self.edit_prediction_preview
 6949                            .set_previous_scroll_position(None);
 6950                    } else {
 6951                        self.edit_prediction_preview
 6952                            .set_previous_scroll_position(Some(
 6953                                position_map.snapshot.scroll_anchor,
 6954                            ));
 6955
 6956                        self.highlight_rows::<EditPredictionPreview>(
 6957                            target..target,
 6958                            cx.theme().colors().editor_highlighted_line_background,
 6959                            RowHighlightOptions {
 6960                                autoscroll: true,
 6961                                ..Default::default()
 6962                            },
 6963                            cx,
 6964                        );
 6965                        self.request_autoscroll(Autoscroll::fit(), cx);
 6966                    }
 6967                }
 6968            }
 6969            InlineCompletion::Edit { edits, .. } => {
 6970                if let Some(provider) = self.edit_prediction_provider() {
 6971                    provider.accept(cx);
 6972                }
 6973
 6974                // Store the transaction ID and selections before applying the edit
 6975                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6976
 6977                let snapshot = self.buffer.read(cx).snapshot(cx);
 6978                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6979
 6980                self.buffer.update(cx, |buffer, cx| {
 6981                    buffer.edit(edits.iter().cloned(), None, cx)
 6982                });
 6983
 6984                self.change_selections(None, window, cx, |s| {
 6985                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6986                });
 6987
 6988                let selections = self.selections.disjoint_anchors();
 6989                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6990                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6991                    if has_new_transaction {
 6992                        self.selection_history
 6993                            .insert_transaction(transaction_id_now, selections);
 6994                    }
 6995                }
 6996
 6997                self.update_visible_inline_completion(window, cx);
 6998                if self.active_inline_completion.is_none() {
 6999                    self.refresh_inline_completion(true, true, window, cx);
 7000                }
 7001
 7002                cx.notify();
 7003            }
 7004        }
 7005
 7006        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7007    }
 7008
 7009    pub fn accept_partial_inline_completion(
 7010        &mut self,
 7011        _: &AcceptPartialEditPrediction,
 7012        window: &mut Window,
 7013        cx: &mut Context<Self>,
 7014    ) {
 7015        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7016            return;
 7017        };
 7018        if self.selections.count() != 1 {
 7019            return;
 7020        }
 7021
 7022        self.report_inline_completion_event(
 7023            active_inline_completion.completion_id.clone(),
 7024            true,
 7025            cx,
 7026        );
 7027
 7028        match &active_inline_completion.completion {
 7029            InlineCompletion::Move { target, .. } => {
 7030                let target = *target;
 7031                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7032                    selections.select_anchor_ranges([target..target]);
 7033                });
 7034            }
 7035            InlineCompletion::Edit { edits, .. } => {
 7036                // Find an insertion that starts at the cursor position.
 7037                let snapshot = self.buffer.read(cx).snapshot(cx);
 7038                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7039                let insertion = edits.iter().find_map(|(range, text)| {
 7040                    let range = range.to_offset(&snapshot);
 7041                    if range.is_empty() && range.start == cursor_offset {
 7042                        Some(text)
 7043                    } else {
 7044                        None
 7045                    }
 7046                });
 7047
 7048                if let Some(text) = insertion {
 7049                    let mut partial_completion = text
 7050                        .chars()
 7051                        .by_ref()
 7052                        .take_while(|c| c.is_alphabetic())
 7053                        .collect::<String>();
 7054                    if partial_completion.is_empty() {
 7055                        partial_completion = text
 7056                            .chars()
 7057                            .by_ref()
 7058                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7059                            .collect::<String>();
 7060                    }
 7061
 7062                    cx.emit(EditorEvent::InputHandled {
 7063                        utf16_range_to_replace: None,
 7064                        text: partial_completion.clone().into(),
 7065                    });
 7066
 7067                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7068
 7069                    self.refresh_inline_completion(true, true, window, cx);
 7070                    cx.notify();
 7071                } else {
 7072                    self.accept_edit_prediction(&Default::default(), window, cx);
 7073                }
 7074            }
 7075        }
 7076    }
 7077
 7078    fn discard_inline_completion(
 7079        &mut self,
 7080        should_report_inline_completion_event: bool,
 7081        cx: &mut Context<Self>,
 7082    ) -> bool {
 7083        if should_report_inline_completion_event {
 7084            let completion_id = self
 7085                .active_inline_completion
 7086                .as_ref()
 7087                .and_then(|active_completion| active_completion.completion_id.clone());
 7088
 7089            self.report_inline_completion_event(completion_id, false, cx);
 7090        }
 7091
 7092        if let Some(provider) = self.edit_prediction_provider() {
 7093            provider.discard(cx);
 7094        }
 7095
 7096        self.take_active_inline_completion(cx)
 7097    }
 7098
 7099    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7100        let Some(provider) = self.edit_prediction_provider() else {
 7101            return;
 7102        };
 7103
 7104        let Some((_, buffer, _)) = self
 7105            .buffer
 7106            .read(cx)
 7107            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7108        else {
 7109            return;
 7110        };
 7111
 7112        let extension = buffer
 7113            .read(cx)
 7114            .file()
 7115            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7116
 7117        let event_type = match accepted {
 7118            true => "Edit Prediction Accepted",
 7119            false => "Edit Prediction Discarded",
 7120        };
 7121        telemetry::event!(
 7122            event_type,
 7123            provider = provider.name(),
 7124            prediction_id = id,
 7125            suggestion_accepted = accepted,
 7126            file_extension = extension,
 7127        );
 7128    }
 7129
 7130    pub fn has_active_inline_completion(&self) -> bool {
 7131        self.active_inline_completion.is_some()
 7132    }
 7133
 7134    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7135        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7136            return false;
 7137        };
 7138
 7139        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7140        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7141        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7142        true
 7143    }
 7144
 7145    /// Returns true when we're displaying the edit prediction popover below the cursor
 7146    /// like we are not previewing and the LSP autocomplete menu is visible
 7147    /// or we are in `when_holding_modifier` mode.
 7148    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7149        if self.edit_prediction_preview_is_active()
 7150            || !self.show_edit_predictions_in_menu()
 7151            || !self.edit_predictions_enabled()
 7152        {
 7153            return false;
 7154        }
 7155
 7156        if self.has_visible_completions_menu() {
 7157            return true;
 7158        }
 7159
 7160        has_completion && self.edit_prediction_requires_modifier()
 7161    }
 7162
 7163    fn handle_modifiers_changed(
 7164        &mut self,
 7165        modifiers: Modifiers,
 7166        position_map: &PositionMap,
 7167        window: &mut Window,
 7168        cx: &mut Context<Self>,
 7169    ) {
 7170        if self.show_edit_predictions_in_menu() {
 7171            self.update_edit_prediction_preview(&modifiers, window, cx);
 7172        }
 7173
 7174        self.update_selection_mode(&modifiers, position_map, window, cx);
 7175
 7176        let mouse_position = window.mouse_position();
 7177        if !position_map.text_hitbox.is_hovered(window) {
 7178            return;
 7179        }
 7180
 7181        self.update_hovered_link(
 7182            position_map.point_for_position(mouse_position),
 7183            &position_map.snapshot,
 7184            modifiers,
 7185            window,
 7186            cx,
 7187        )
 7188    }
 7189
 7190    fn multi_cursor_modifier(
 7191        cursor_event: bool,
 7192        modifiers: &Modifiers,
 7193        cx: &mut Context<Self>,
 7194    ) -> bool {
 7195        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7196        if cursor_event {
 7197            match multi_cursor_setting {
 7198                MultiCursorModifier::Alt => modifiers.alt,
 7199                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7200            }
 7201        } else {
 7202            match multi_cursor_setting {
 7203                MultiCursorModifier::Alt => modifiers.secondary(),
 7204                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7205            }
 7206        }
 7207    }
 7208
 7209    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7210        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7211    }
 7212
 7213    fn update_selection_mode(
 7214        &mut self,
 7215        modifiers: &Modifiers,
 7216        position_map: &PositionMap,
 7217        window: &mut Window,
 7218        cx: &mut Context<Self>,
 7219    ) {
 7220        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7221        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7222            || self.selections.pending.is_none()
 7223        {
 7224            return;
 7225        }
 7226
 7227        let mouse_position = window.mouse_position();
 7228        let point_for_position = position_map.point_for_position(mouse_position);
 7229        let position = point_for_position.previous_valid;
 7230
 7231        self.select(
 7232            SelectPhase::BeginColumnar {
 7233                position,
 7234                reset: false,
 7235                goal_column: point_for_position.exact_unclipped.column(),
 7236            },
 7237            window,
 7238            cx,
 7239        );
 7240    }
 7241
 7242    fn update_edit_prediction_preview(
 7243        &mut self,
 7244        modifiers: &Modifiers,
 7245        window: &mut Window,
 7246        cx: &mut Context<Self>,
 7247    ) {
 7248        let mut modifiers_held = false;
 7249        if let Some(accept_keystroke) = self
 7250            .accept_edit_prediction_keybind(false, window, cx)
 7251            .keystroke()
 7252        {
 7253            modifiers_held = modifiers_held
 7254                || (&accept_keystroke.modifiers == modifiers
 7255                    && accept_keystroke.modifiers.modified());
 7256        };
 7257        if let Some(accept_partial_keystroke) = self
 7258            .accept_edit_prediction_keybind(true, window, cx)
 7259            .keystroke()
 7260        {
 7261            modifiers_held = modifiers_held
 7262                || (&accept_partial_keystroke.modifiers == modifiers
 7263                    && accept_partial_keystroke.modifiers.modified());
 7264        }
 7265
 7266        if modifiers_held {
 7267            if matches!(
 7268                self.edit_prediction_preview,
 7269                EditPredictionPreview::Inactive { .. }
 7270            ) {
 7271                self.edit_prediction_preview = EditPredictionPreview::Active {
 7272                    previous_scroll_position: None,
 7273                    since: Instant::now(),
 7274                };
 7275
 7276                self.update_visible_inline_completion(window, cx);
 7277                cx.notify();
 7278            }
 7279        } else if let EditPredictionPreview::Active {
 7280            previous_scroll_position,
 7281            since,
 7282        } = self.edit_prediction_preview
 7283        {
 7284            if let (Some(previous_scroll_position), Some(position_map)) =
 7285                (previous_scroll_position, self.last_position_map.as_ref())
 7286            {
 7287                self.set_scroll_position(
 7288                    previous_scroll_position
 7289                        .scroll_position(&position_map.snapshot.display_snapshot),
 7290                    window,
 7291                    cx,
 7292                );
 7293            }
 7294
 7295            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7296                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7297            };
 7298            self.clear_row_highlights::<EditPredictionPreview>();
 7299            self.update_visible_inline_completion(window, cx);
 7300            cx.notify();
 7301        }
 7302    }
 7303
 7304    fn update_visible_inline_completion(
 7305        &mut self,
 7306        _window: &mut Window,
 7307        cx: &mut Context<Self>,
 7308    ) -> Option<()> {
 7309        let selection = self.selections.newest_anchor();
 7310        let cursor = selection.head();
 7311        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7312        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7313        let excerpt_id = cursor.excerpt_id;
 7314
 7315        let show_in_menu = self.show_edit_predictions_in_menu();
 7316        let completions_menu_has_precedence = !show_in_menu
 7317            && (self.context_menu.borrow().is_some()
 7318                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7319
 7320        if completions_menu_has_precedence
 7321            || !offset_selection.is_empty()
 7322            || self
 7323                .active_inline_completion
 7324                .as_ref()
 7325                .map_or(false, |completion| {
 7326                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7327                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7328                    !invalidation_range.contains(&offset_selection.head())
 7329                })
 7330        {
 7331            self.discard_inline_completion(false, cx);
 7332            return None;
 7333        }
 7334
 7335        self.take_active_inline_completion(cx);
 7336        let Some(provider) = self.edit_prediction_provider() else {
 7337            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7338            return None;
 7339        };
 7340
 7341        let (buffer, cursor_buffer_position) =
 7342            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7343
 7344        self.edit_prediction_settings =
 7345            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7346
 7347        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7348
 7349        if self.edit_prediction_indent_conflict {
 7350            let cursor_point = cursor.to_point(&multibuffer);
 7351
 7352            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7353
 7354            if let Some((_, indent)) = indents.iter().next() {
 7355                if indent.len == cursor_point.column {
 7356                    self.edit_prediction_indent_conflict = false;
 7357                }
 7358            }
 7359        }
 7360
 7361        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7362        let edits = inline_completion
 7363            .edits
 7364            .into_iter()
 7365            .flat_map(|(range, new_text)| {
 7366                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7367                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7368                Some((start..end, new_text))
 7369            })
 7370            .collect::<Vec<_>>();
 7371        if edits.is_empty() {
 7372            return None;
 7373        }
 7374
 7375        let first_edit_start = edits.first().unwrap().0.start;
 7376        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7377        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7378
 7379        let last_edit_end = edits.last().unwrap().0.end;
 7380        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7381        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7382
 7383        let cursor_row = cursor.to_point(&multibuffer).row;
 7384
 7385        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7386
 7387        let mut inlay_ids = Vec::new();
 7388        let invalidation_row_range;
 7389        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7390            Some(cursor_row..edit_end_row)
 7391        } else if cursor_row > edit_end_row {
 7392            Some(edit_start_row..cursor_row)
 7393        } else {
 7394            None
 7395        };
 7396        let is_move =
 7397            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7398        let completion = if is_move {
 7399            invalidation_row_range =
 7400                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7401            let target = first_edit_start;
 7402            InlineCompletion::Move { target, snapshot }
 7403        } else {
 7404            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7405                && !self.inline_completions_hidden_for_vim_mode;
 7406
 7407            if show_completions_in_buffer {
 7408                if edits
 7409                    .iter()
 7410                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7411                {
 7412                    let mut inlays = Vec::new();
 7413                    for (range, new_text) in &edits {
 7414                        let inlay = Inlay::inline_completion(
 7415                            post_inc(&mut self.next_inlay_id),
 7416                            range.start,
 7417                            new_text.as_str(),
 7418                        );
 7419                        inlay_ids.push(inlay.id);
 7420                        inlays.push(inlay);
 7421                    }
 7422
 7423                    self.splice_inlays(&[], inlays, cx);
 7424                } else {
 7425                    let background_color = cx.theme().status().deleted_background;
 7426                    self.highlight_text::<InlineCompletionHighlight>(
 7427                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7428                        HighlightStyle {
 7429                            background_color: Some(background_color),
 7430                            ..Default::default()
 7431                        },
 7432                        cx,
 7433                    );
 7434                }
 7435            }
 7436
 7437            invalidation_row_range = edit_start_row..edit_end_row;
 7438
 7439            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7440                if provider.show_tab_accept_marker() {
 7441                    EditDisplayMode::TabAccept
 7442                } else {
 7443                    EditDisplayMode::Inline
 7444                }
 7445            } else {
 7446                EditDisplayMode::DiffPopover
 7447            };
 7448
 7449            InlineCompletion::Edit {
 7450                edits,
 7451                edit_preview: inline_completion.edit_preview,
 7452                display_mode,
 7453                snapshot,
 7454            }
 7455        };
 7456
 7457        let invalidation_range = multibuffer
 7458            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7459            ..multibuffer.anchor_after(Point::new(
 7460                invalidation_row_range.end,
 7461                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7462            ));
 7463
 7464        self.stale_inline_completion_in_menu = None;
 7465        self.active_inline_completion = Some(InlineCompletionState {
 7466            inlay_ids,
 7467            completion,
 7468            completion_id: inline_completion.id,
 7469            invalidation_range,
 7470        });
 7471
 7472        cx.notify();
 7473
 7474        Some(())
 7475    }
 7476
 7477    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7478        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7479    }
 7480
 7481    fn clear_tasks(&mut self) {
 7482        self.tasks.clear()
 7483    }
 7484
 7485    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7486        if self.tasks.insert(key, value).is_some() {
 7487            // This case should hopefully be rare, but just in case...
 7488            log::error!(
 7489                "multiple different run targets found on a single line, only the last target will be rendered"
 7490            )
 7491        }
 7492    }
 7493
 7494    /// Get all display points of breakpoints that will be rendered within editor
 7495    ///
 7496    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7497    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7498    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7499    fn active_breakpoints(
 7500        &self,
 7501        range: Range<DisplayRow>,
 7502        window: &mut Window,
 7503        cx: &mut Context<Self>,
 7504    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7505        let mut breakpoint_display_points = HashMap::default();
 7506
 7507        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7508            return breakpoint_display_points;
 7509        };
 7510
 7511        let snapshot = self.snapshot(window, cx);
 7512
 7513        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7514        let Some(project) = self.project.as_ref() else {
 7515            return breakpoint_display_points;
 7516        };
 7517
 7518        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7519            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7520
 7521        for (buffer_snapshot, range, excerpt_id) in
 7522            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7523        {
 7524            let Some(buffer) = project
 7525                .read(cx)
 7526                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7527            else {
 7528                continue;
 7529            };
 7530            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7531                &buffer,
 7532                Some(
 7533                    buffer_snapshot.anchor_before(range.start)
 7534                        ..buffer_snapshot.anchor_after(range.end),
 7535                ),
 7536                buffer_snapshot,
 7537                cx,
 7538            );
 7539            for (breakpoint, state) in breakpoints {
 7540                let multi_buffer_anchor =
 7541                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7542                let position = multi_buffer_anchor
 7543                    .to_point(&multi_buffer_snapshot)
 7544                    .to_display_point(&snapshot);
 7545
 7546                breakpoint_display_points.insert(
 7547                    position.row(),
 7548                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7549                );
 7550            }
 7551        }
 7552
 7553        breakpoint_display_points
 7554    }
 7555
 7556    fn breakpoint_context_menu(
 7557        &self,
 7558        anchor: Anchor,
 7559        window: &mut Window,
 7560        cx: &mut Context<Self>,
 7561    ) -> Entity<ui::ContextMenu> {
 7562        let weak_editor = cx.weak_entity();
 7563        let focus_handle = self.focus_handle(cx);
 7564
 7565        let row = self
 7566            .buffer
 7567            .read(cx)
 7568            .snapshot(cx)
 7569            .summary_for_anchor::<Point>(&anchor)
 7570            .row;
 7571
 7572        let breakpoint = self
 7573            .breakpoint_at_row(row, window, cx)
 7574            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7575
 7576        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7577            "Edit Log Breakpoint"
 7578        } else {
 7579            "Set Log Breakpoint"
 7580        };
 7581
 7582        let condition_breakpoint_msg = if breakpoint
 7583            .as_ref()
 7584            .is_some_and(|bp| bp.1.condition.is_some())
 7585        {
 7586            "Edit Condition Breakpoint"
 7587        } else {
 7588            "Set Condition Breakpoint"
 7589        };
 7590
 7591        let hit_condition_breakpoint_msg = if breakpoint
 7592            .as_ref()
 7593            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7594        {
 7595            "Edit Hit Condition Breakpoint"
 7596        } else {
 7597            "Set Hit Condition Breakpoint"
 7598        };
 7599
 7600        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7601            "Unset Breakpoint"
 7602        } else {
 7603            "Set Breakpoint"
 7604        };
 7605
 7606        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7607
 7608        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7609            BreakpointState::Enabled => Some("Disable"),
 7610            BreakpointState::Disabled => Some("Enable"),
 7611        });
 7612
 7613        let (anchor, breakpoint) =
 7614            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7615
 7616        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7617            menu.on_blur_subscription(Subscription::new(|| {}))
 7618                .context(focus_handle)
 7619                .when(run_to_cursor, |this| {
 7620                    let weak_editor = weak_editor.clone();
 7621                    this.entry("Run to cursor", None, move |window, cx| {
 7622                        weak_editor
 7623                            .update(cx, |editor, cx| {
 7624                                editor.change_selections(None, window, cx, |s| {
 7625                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7626                                });
 7627                            })
 7628                            .ok();
 7629
 7630                        window.dispatch_action(Box::new(RunToCursor), cx);
 7631                    })
 7632                    .separator()
 7633                })
 7634                .when_some(toggle_state_msg, |this, msg| {
 7635                    this.entry(msg, None, {
 7636                        let weak_editor = weak_editor.clone();
 7637                        let breakpoint = breakpoint.clone();
 7638                        move |_window, cx| {
 7639                            weak_editor
 7640                                .update(cx, |this, cx| {
 7641                                    this.edit_breakpoint_at_anchor(
 7642                                        anchor,
 7643                                        breakpoint.as_ref().clone(),
 7644                                        BreakpointEditAction::InvertState,
 7645                                        cx,
 7646                                    );
 7647                                })
 7648                                .log_err();
 7649                        }
 7650                    })
 7651                })
 7652                .entry(set_breakpoint_msg, None, {
 7653                    let weak_editor = weak_editor.clone();
 7654                    let breakpoint = breakpoint.clone();
 7655                    move |_window, cx| {
 7656                        weak_editor
 7657                            .update(cx, |this, cx| {
 7658                                this.edit_breakpoint_at_anchor(
 7659                                    anchor,
 7660                                    breakpoint.as_ref().clone(),
 7661                                    BreakpointEditAction::Toggle,
 7662                                    cx,
 7663                                );
 7664                            })
 7665                            .log_err();
 7666                    }
 7667                })
 7668                .entry(log_breakpoint_msg, None, {
 7669                    let breakpoint = breakpoint.clone();
 7670                    let weak_editor = weak_editor.clone();
 7671                    move |window, cx| {
 7672                        weak_editor
 7673                            .update(cx, |this, cx| {
 7674                                this.add_edit_breakpoint_block(
 7675                                    anchor,
 7676                                    breakpoint.as_ref(),
 7677                                    BreakpointPromptEditAction::Log,
 7678                                    window,
 7679                                    cx,
 7680                                );
 7681                            })
 7682                            .log_err();
 7683                    }
 7684                })
 7685                .entry(condition_breakpoint_msg, None, {
 7686                    let breakpoint = breakpoint.clone();
 7687                    let weak_editor = weak_editor.clone();
 7688                    move |window, cx| {
 7689                        weak_editor
 7690                            .update(cx, |this, cx| {
 7691                                this.add_edit_breakpoint_block(
 7692                                    anchor,
 7693                                    breakpoint.as_ref(),
 7694                                    BreakpointPromptEditAction::Condition,
 7695                                    window,
 7696                                    cx,
 7697                                );
 7698                            })
 7699                            .log_err();
 7700                    }
 7701                })
 7702                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7703                    weak_editor
 7704                        .update(cx, |this, cx| {
 7705                            this.add_edit_breakpoint_block(
 7706                                anchor,
 7707                                breakpoint.as_ref(),
 7708                                BreakpointPromptEditAction::HitCondition,
 7709                                window,
 7710                                cx,
 7711                            );
 7712                        })
 7713                        .log_err();
 7714                })
 7715        })
 7716    }
 7717
 7718    fn render_breakpoint(
 7719        &self,
 7720        position: Anchor,
 7721        row: DisplayRow,
 7722        breakpoint: &Breakpoint,
 7723        state: Option<BreakpointSessionState>,
 7724        cx: &mut Context<Self>,
 7725    ) -> IconButton {
 7726        let is_rejected = state.is_some_and(|s| !s.verified);
 7727        // Is it a breakpoint that shows up when hovering over gutter?
 7728        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7729            (false, false),
 7730            |PhantomBreakpointIndicator {
 7731                 is_active,
 7732                 display_row,
 7733                 collides_with_existing_breakpoint,
 7734             }| {
 7735                (
 7736                    is_active && display_row == row,
 7737                    collides_with_existing_breakpoint,
 7738                )
 7739            },
 7740        );
 7741
 7742        let (color, icon) = {
 7743            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7744                (false, false) => ui::IconName::DebugBreakpoint,
 7745                (true, false) => ui::IconName::DebugLogBreakpoint,
 7746                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7747                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7748            };
 7749
 7750            let color = if is_phantom {
 7751                Color::Hint
 7752            } else if is_rejected {
 7753                Color::Disabled
 7754            } else {
 7755                Color::Debugger
 7756            };
 7757
 7758            (color, icon)
 7759        };
 7760
 7761        let breakpoint = Arc::from(breakpoint.clone());
 7762
 7763        let alt_as_text = gpui::Keystroke {
 7764            modifiers: Modifiers::secondary_key(),
 7765            ..Default::default()
 7766        };
 7767        let primary_action_text = if breakpoint.is_disabled() {
 7768            "Enable breakpoint"
 7769        } else if is_phantom && !collides_with_existing {
 7770            "Set breakpoint"
 7771        } else {
 7772            "Unset breakpoint"
 7773        };
 7774        let focus_handle = self.focus_handle.clone();
 7775
 7776        let meta = if is_rejected {
 7777            SharedString::from("No executable code is associated with this line.")
 7778        } else if collides_with_existing && !breakpoint.is_disabled() {
 7779            SharedString::from(format!(
 7780                "{alt_as_text}-click to disable,\nright-click for more options."
 7781            ))
 7782        } else {
 7783            SharedString::from("Right-click for more options.")
 7784        };
 7785        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7786            .icon_size(IconSize::XSmall)
 7787            .size(ui::ButtonSize::None)
 7788            .when(is_rejected, |this| {
 7789                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7790            })
 7791            .icon_color(color)
 7792            .style(ButtonStyle::Transparent)
 7793            .on_click(cx.listener({
 7794                let breakpoint = breakpoint.clone();
 7795
 7796                move |editor, event: &ClickEvent, window, cx| {
 7797                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7798                        BreakpointEditAction::InvertState
 7799                    } else {
 7800                        BreakpointEditAction::Toggle
 7801                    };
 7802
 7803                    window.focus(&editor.focus_handle(cx));
 7804                    editor.edit_breakpoint_at_anchor(
 7805                        position,
 7806                        breakpoint.as_ref().clone(),
 7807                        edit_action,
 7808                        cx,
 7809                    );
 7810                }
 7811            }))
 7812            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7813                editor.set_breakpoint_context_menu(
 7814                    row,
 7815                    Some(position),
 7816                    event.down.position,
 7817                    window,
 7818                    cx,
 7819                );
 7820            }))
 7821            .tooltip(move |window, cx| {
 7822                Tooltip::with_meta_in(
 7823                    primary_action_text,
 7824                    Some(&ToggleBreakpoint),
 7825                    meta.clone(),
 7826                    &focus_handle,
 7827                    window,
 7828                    cx,
 7829                )
 7830            })
 7831    }
 7832
 7833    fn build_tasks_context(
 7834        project: &Entity<Project>,
 7835        buffer: &Entity<Buffer>,
 7836        buffer_row: u32,
 7837        tasks: &Arc<RunnableTasks>,
 7838        cx: &mut Context<Self>,
 7839    ) -> Task<Option<task::TaskContext>> {
 7840        let position = Point::new(buffer_row, tasks.column);
 7841        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7842        let location = Location {
 7843            buffer: buffer.clone(),
 7844            range: range_start..range_start,
 7845        };
 7846        // Fill in the environmental variables from the tree-sitter captures
 7847        let mut captured_task_variables = TaskVariables::default();
 7848        for (capture_name, value) in tasks.extra_variables.clone() {
 7849            captured_task_variables.insert(
 7850                task::VariableName::Custom(capture_name.into()),
 7851                value.clone(),
 7852            );
 7853        }
 7854        project.update(cx, |project, cx| {
 7855            project.task_store().update(cx, |task_store, cx| {
 7856                task_store.task_context_for_location(captured_task_variables, location, cx)
 7857            })
 7858        })
 7859    }
 7860
 7861    pub fn spawn_nearest_task(
 7862        &mut self,
 7863        action: &SpawnNearestTask,
 7864        window: &mut Window,
 7865        cx: &mut Context<Self>,
 7866    ) {
 7867        let Some((workspace, _)) = self.workspace.clone() else {
 7868            return;
 7869        };
 7870        let Some(project) = self.project.clone() else {
 7871            return;
 7872        };
 7873
 7874        // Try to find a closest, enclosing node using tree-sitter that has a
 7875        // task
 7876        let Some((buffer, buffer_row, tasks)) = self
 7877            .find_enclosing_node_task(cx)
 7878            // Or find the task that's closest in row-distance.
 7879            .or_else(|| self.find_closest_task(cx))
 7880        else {
 7881            return;
 7882        };
 7883
 7884        let reveal_strategy = action.reveal;
 7885        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7886        cx.spawn_in(window, async move |_, cx| {
 7887            let context = task_context.await?;
 7888            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7889
 7890            let resolved = &mut resolved_task.resolved;
 7891            resolved.reveal = reveal_strategy;
 7892
 7893            workspace
 7894                .update_in(cx, |workspace, window, cx| {
 7895                    workspace.schedule_resolved_task(
 7896                        task_source_kind,
 7897                        resolved_task,
 7898                        false,
 7899                        window,
 7900                        cx,
 7901                    );
 7902                })
 7903                .ok()
 7904        })
 7905        .detach();
 7906    }
 7907
 7908    fn find_closest_task(
 7909        &mut self,
 7910        cx: &mut Context<Self>,
 7911    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7912        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7913
 7914        let ((buffer_id, row), tasks) = self
 7915            .tasks
 7916            .iter()
 7917            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7918
 7919        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7920        let tasks = Arc::new(tasks.to_owned());
 7921        Some((buffer, *row, tasks))
 7922    }
 7923
 7924    fn find_enclosing_node_task(
 7925        &mut self,
 7926        cx: &mut Context<Self>,
 7927    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7928        let snapshot = self.buffer.read(cx).snapshot(cx);
 7929        let offset = self.selections.newest::<usize>(cx).head();
 7930        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7931        let buffer_id = excerpt.buffer().remote_id();
 7932
 7933        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7934        let mut cursor = layer.node().walk();
 7935
 7936        while cursor.goto_first_child_for_byte(offset).is_some() {
 7937            if cursor.node().end_byte() == offset {
 7938                cursor.goto_next_sibling();
 7939            }
 7940        }
 7941
 7942        // Ascend to the smallest ancestor that contains the range and has a task.
 7943        loop {
 7944            let node = cursor.node();
 7945            let node_range = node.byte_range();
 7946            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7947
 7948            // Check if this node contains our offset
 7949            if node_range.start <= offset && node_range.end >= offset {
 7950                // If it contains offset, check for task
 7951                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7952                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7953                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7954                }
 7955            }
 7956
 7957            if !cursor.goto_parent() {
 7958                break;
 7959            }
 7960        }
 7961        None
 7962    }
 7963
 7964    fn render_run_indicator(
 7965        &self,
 7966        _style: &EditorStyle,
 7967        is_active: bool,
 7968        row: DisplayRow,
 7969        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7970        cx: &mut Context<Self>,
 7971    ) -> IconButton {
 7972        let color = Color::Muted;
 7973        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7974
 7975        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7976            .shape(ui::IconButtonShape::Square)
 7977            .icon_size(IconSize::XSmall)
 7978            .icon_color(color)
 7979            .toggle_state(is_active)
 7980            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7981                let quick_launch = e.down.button == MouseButton::Left;
 7982                window.focus(&editor.focus_handle(cx));
 7983                editor.toggle_code_actions(
 7984                    &ToggleCodeActions {
 7985                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7986                        quick_launch,
 7987                    },
 7988                    window,
 7989                    cx,
 7990                );
 7991            }))
 7992            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7993                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7994            }))
 7995    }
 7996
 7997    pub fn context_menu_visible(&self) -> bool {
 7998        !self.edit_prediction_preview_is_active()
 7999            && self
 8000                .context_menu
 8001                .borrow()
 8002                .as_ref()
 8003                .map_or(false, |menu| menu.visible())
 8004    }
 8005
 8006    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8007        self.context_menu
 8008            .borrow()
 8009            .as_ref()
 8010            .map(|menu| menu.origin())
 8011    }
 8012
 8013    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8014        self.context_menu_options = Some(options);
 8015    }
 8016
 8017    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8018    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8019
 8020    fn render_edit_prediction_popover(
 8021        &mut self,
 8022        text_bounds: &Bounds<Pixels>,
 8023        content_origin: gpui::Point<Pixels>,
 8024        right_margin: Pixels,
 8025        editor_snapshot: &EditorSnapshot,
 8026        visible_row_range: Range<DisplayRow>,
 8027        scroll_top: f32,
 8028        scroll_bottom: f32,
 8029        line_layouts: &[LineWithInvisibles],
 8030        line_height: Pixels,
 8031        scroll_pixel_position: gpui::Point<Pixels>,
 8032        newest_selection_head: Option<DisplayPoint>,
 8033        editor_width: Pixels,
 8034        style: &EditorStyle,
 8035        window: &mut Window,
 8036        cx: &mut App,
 8037    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8038        if self.mode().is_minimap() {
 8039            return None;
 8040        }
 8041        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8042
 8043        if self.edit_prediction_visible_in_cursor_popover(true) {
 8044            return None;
 8045        }
 8046
 8047        match &active_inline_completion.completion {
 8048            InlineCompletion::Move { target, .. } => {
 8049                let target_display_point = target.to_display_point(editor_snapshot);
 8050
 8051                if self.edit_prediction_requires_modifier() {
 8052                    if !self.edit_prediction_preview_is_active() {
 8053                        return None;
 8054                    }
 8055
 8056                    self.render_edit_prediction_modifier_jump_popover(
 8057                        text_bounds,
 8058                        content_origin,
 8059                        visible_row_range,
 8060                        line_layouts,
 8061                        line_height,
 8062                        scroll_pixel_position,
 8063                        newest_selection_head,
 8064                        target_display_point,
 8065                        window,
 8066                        cx,
 8067                    )
 8068                } else {
 8069                    self.render_edit_prediction_eager_jump_popover(
 8070                        text_bounds,
 8071                        content_origin,
 8072                        editor_snapshot,
 8073                        visible_row_range,
 8074                        scroll_top,
 8075                        scroll_bottom,
 8076                        line_height,
 8077                        scroll_pixel_position,
 8078                        target_display_point,
 8079                        editor_width,
 8080                        window,
 8081                        cx,
 8082                    )
 8083                }
 8084            }
 8085            InlineCompletion::Edit {
 8086                display_mode: EditDisplayMode::Inline,
 8087                ..
 8088            } => None,
 8089            InlineCompletion::Edit {
 8090                display_mode: EditDisplayMode::TabAccept,
 8091                edits,
 8092                ..
 8093            } => {
 8094                let range = &edits.first()?.0;
 8095                let target_display_point = range.end.to_display_point(editor_snapshot);
 8096
 8097                self.render_edit_prediction_end_of_line_popover(
 8098                    "Accept",
 8099                    editor_snapshot,
 8100                    visible_row_range,
 8101                    target_display_point,
 8102                    line_height,
 8103                    scroll_pixel_position,
 8104                    content_origin,
 8105                    editor_width,
 8106                    window,
 8107                    cx,
 8108                )
 8109            }
 8110            InlineCompletion::Edit {
 8111                edits,
 8112                edit_preview,
 8113                display_mode: EditDisplayMode::DiffPopover,
 8114                snapshot,
 8115            } => self.render_edit_prediction_diff_popover(
 8116                text_bounds,
 8117                content_origin,
 8118                right_margin,
 8119                editor_snapshot,
 8120                visible_row_range,
 8121                line_layouts,
 8122                line_height,
 8123                scroll_pixel_position,
 8124                newest_selection_head,
 8125                editor_width,
 8126                style,
 8127                edits,
 8128                edit_preview,
 8129                snapshot,
 8130                window,
 8131                cx,
 8132            ),
 8133        }
 8134    }
 8135
 8136    fn render_edit_prediction_modifier_jump_popover(
 8137        &mut self,
 8138        text_bounds: &Bounds<Pixels>,
 8139        content_origin: gpui::Point<Pixels>,
 8140        visible_row_range: Range<DisplayRow>,
 8141        line_layouts: &[LineWithInvisibles],
 8142        line_height: Pixels,
 8143        scroll_pixel_position: gpui::Point<Pixels>,
 8144        newest_selection_head: Option<DisplayPoint>,
 8145        target_display_point: DisplayPoint,
 8146        window: &mut Window,
 8147        cx: &mut App,
 8148    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8149        let scrolled_content_origin =
 8150            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8151
 8152        const SCROLL_PADDING_Y: Pixels = px(12.);
 8153
 8154        if target_display_point.row() < visible_row_range.start {
 8155            return self.render_edit_prediction_scroll_popover(
 8156                |_| SCROLL_PADDING_Y,
 8157                IconName::ArrowUp,
 8158                visible_row_range,
 8159                line_layouts,
 8160                newest_selection_head,
 8161                scrolled_content_origin,
 8162                window,
 8163                cx,
 8164            );
 8165        } else if target_display_point.row() >= visible_row_range.end {
 8166            return self.render_edit_prediction_scroll_popover(
 8167                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8168                IconName::ArrowDown,
 8169                visible_row_range,
 8170                line_layouts,
 8171                newest_selection_head,
 8172                scrolled_content_origin,
 8173                window,
 8174                cx,
 8175            );
 8176        }
 8177
 8178        const POLE_WIDTH: Pixels = px(2.);
 8179
 8180        let line_layout =
 8181            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8182        let target_column = target_display_point.column() as usize;
 8183
 8184        let target_x = line_layout.x_for_index(target_column);
 8185        let target_y =
 8186            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8187
 8188        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8189
 8190        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8191        border_color.l += 0.001;
 8192
 8193        let mut element = v_flex()
 8194            .items_end()
 8195            .when(flag_on_right, |el| el.items_start())
 8196            .child(if flag_on_right {
 8197                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8198                    .rounded_bl(px(0.))
 8199                    .rounded_tl(px(0.))
 8200                    .border_l_2()
 8201                    .border_color(border_color)
 8202            } else {
 8203                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8204                    .rounded_br(px(0.))
 8205                    .rounded_tr(px(0.))
 8206                    .border_r_2()
 8207                    .border_color(border_color)
 8208            })
 8209            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8210            .into_any();
 8211
 8212        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8213
 8214        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8215            - point(
 8216                if flag_on_right {
 8217                    POLE_WIDTH
 8218                } else {
 8219                    size.width - POLE_WIDTH
 8220                },
 8221                size.height - line_height,
 8222            );
 8223
 8224        origin.x = origin.x.max(content_origin.x);
 8225
 8226        element.prepaint_at(origin, window, cx);
 8227
 8228        Some((element, origin))
 8229    }
 8230
 8231    fn render_edit_prediction_scroll_popover(
 8232        &mut self,
 8233        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8234        scroll_icon: IconName,
 8235        visible_row_range: Range<DisplayRow>,
 8236        line_layouts: &[LineWithInvisibles],
 8237        newest_selection_head: Option<DisplayPoint>,
 8238        scrolled_content_origin: gpui::Point<Pixels>,
 8239        window: &mut Window,
 8240        cx: &mut App,
 8241    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8242        let mut element = self
 8243            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8244            .into_any();
 8245
 8246        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8247
 8248        let cursor = newest_selection_head?;
 8249        let cursor_row_layout =
 8250            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8251        let cursor_column = cursor.column() as usize;
 8252
 8253        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8254
 8255        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8256
 8257        element.prepaint_at(origin, window, cx);
 8258        Some((element, origin))
 8259    }
 8260
 8261    fn render_edit_prediction_eager_jump_popover(
 8262        &mut self,
 8263        text_bounds: &Bounds<Pixels>,
 8264        content_origin: gpui::Point<Pixels>,
 8265        editor_snapshot: &EditorSnapshot,
 8266        visible_row_range: Range<DisplayRow>,
 8267        scroll_top: f32,
 8268        scroll_bottom: f32,
 8269        line_height: Pixels,
 8270        scroll_pixel_position: gpui::Point<Pixels>,
 8271        target_display_point: DisplayPoint,
 8272        editor_width: Pixels,
 8273        window: &mut Window,
 8274        cx: &mut App,
 8275    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8276        if target_display_point.row().as_f32() < scroll_top {
 8277            let mut element = self
 8278                .render_edit_prediction_line_popover(
 8279                    "Jump to Edit",
 8280                    Some(IconName::ArrowUp),
 8281                    window,
 8282                    cx,
 8283                )?
 8284                .into_any();
 8285
 8286            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8287            let offset = point(
 8288                (text_bounds.size.width - size.width) / 2.,
 8289                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8290            );
 8291
 8292            let origin = text_bounds.origin + offset;
 8293            element.prepaint_at(origin, window, cx);
 8294            Some((element, origin))
 8295        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8296            let mut element = self
 8297                .render_edit_prediction_line_popover(
 8298                    "Jump to Edit",
 8299                    Some(IconName::ArrowDown),
 8300                    window,
 8301                    cx,
 8302                )?
 8303                .into_any();
 8304
 8305            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8306            let offset = point(
 8307                (text_bounds.size.width - size.width) / 2.,
 8308                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8309            );
 8310
 8311            let origin = text_bounds.origin + offset;
 8312            element.prepaint_at(origin, window, cx);
 8313            Some((element, origin))
 8314        } else {
 8315            self.render_edit_prediction_end_of_line_popover(
 8316                "Jump to Edit",
 8317                editor_snapshot,
 8318                visible_row_range,
 8319                target_display_point,
 8320                line_height,
 8321                scroll_pixel_position,
 8322                content_origin,
 8323                editor_width,
 8324                window,
 8325                cx,
 8326            )
 8327        }
 8328    }
 8329
 8330    fn render_edit_prediction_end_of_line_popover(
 8331        self: &mut Editor,
 8332        label: &'static str,
 8333        editor_snapshot: &EditorSnapshot,
 8334        visible_row_range: Range<DisplayRow>,
 8335        target_display_point: DisplayPoint,
 8336        line_height: Pixels,
 8337        scroll_pixel_position: gpui::Point<Pixels>,
 8338        content_origin: gpui::Point<Pixels>,
 8339        editor_width: Pixels,
 8340        window: &mut Window,
 8341        cx: &mut App,
 8342    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8343        let target_line_end = DisplayPoint::new(
 8344            target_display_point.row(),
 8345            editor_snapshot.line_len(target_display_point.row()),
 8346        );
 8347
 8348        let mut element = self
 8349            .render_edit_prediction_line_popover(label, None, window, cx)?
 8350            .into_any();
 8351
 8352        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8353
 8354        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8355
 8356        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8357        let mut origin = start_point
 8358            + line_origin
 8359            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8360        origin.x = origin.x.max(content_origin.x);
 8361
 8362        let max_x = content_origin.x + editor_width - size.width;
 8363
 8364        if origin.x > max_x {
 8365            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8366
 8367            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8368                origin.y += offset;
 8369                IconName::ArrowUp
 8370            } else {
 8371                origin.y -= offset;
 8372                IconName::ArrowDown
 8373            };
 8374
 8375            element = self
 8376                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8377                .into_any();
 8378
 8379            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8380
 8381            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8382        }
 8383
 8384        element.prepaint_at(origin, window, cx);
 8385        Some((element, origin))
 8386    }
 8387
 8388    fn render_edit_prediction_diff_popover(
 8389        self: &Editor,
 8390        text_bounds: &Bounds<Pixels>,
 8391        content_origin: gpui::Point<Pixels>,
 8392        right_margin: Pixels,
 8393        editor_snapshot: &EditorSnapshot,
 8394        visible_row_range: Range<DisplayRow>,
 8395        line_layouts: &[LineWithInvisibles],
 8396        line_height: Pixels,
 8397        scroll_pixel_position: gpui::Point<Pixels>,
 8398        newest_selection_head: Option<DisplayPoint>,
 8399        editor_width: Pixels,
 8400        style: &EditorStyle,
 8401        edits: &Vec<(Range<Anchor>, String)>,
 8402        edit_preview: &Option<language::EditPreview>,
 8403        snapshot: &language::BufferSnapshot,
 8404        window: &mut Window,
 8405        cx: &mut App,
 8406    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8407        let edit_start = edits
 8408            .first()
 8409            .unwrap()
 8410            .0
 8411            .start
 8412            .to_display_point(editor_snapshot);
 8413        let edit_end = edits
 8414            .last()
 8415            .unwrap()
 8416            .0
 8417            .end
 8418            .to_display_point(editor_snapshot);
 8419
 8420        let is_visible = visible_row_range.contains(&edit_start.row())
 8421            || visible_row_range.contains(&edit_end.row());
 8422        if !is_visible {
 8423            return None;
 8424        }
 8425
 8426        let highlighted_edits =
 8427            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8428
 8429        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8430        let line_count = highlighted_edits.text.lines().count();
 8431
 8432        const BORDER_WIDTH: Pixels = px(1.);
 8433
 8434        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8435        let has_keybind = keybind.is_some();
 8436
 8437        let mut element = h_flex()
 8438            .items_start()
 8439            .child(
 8440                h_flex()
 8441                    .bg(cx.theme().colors().editor_background)
 8442                    .border(BORDER_WIDTH)
 8443                    .shadow_sm()
 8444                    .border_color(cx.theme().colors().border)
 8445                    .rounded_l_lg()
 8446                    .when(line_count > 1, |el| el.rounded_br_lg())
 8447                    .pr_1()
 8448                    .child(styled_text),
 8449            )
 8450            .child(
 8451                h_flex()
 8452                    .h(line_height + BORDER_WIDTH * 2.)
 8453                    .px_1p5()
 8454                    .gap_1()
 8455                    // Workaround: For some reason, there's a gap if we don't do this
 8456                    .ml(-BORDER_WIDTH)
 8457                    .shadow(vec![gpui::BoxShadow {
 8458                        color: gpui::black().opacity(0.05),
 8459                        offset: point(px(1.), px(1.)),
 8460                        blur_radius: px(2.),
 8461                        spread_radius: px(0.),
 8462                    }])
 8463                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8464                    .border(BORDER_WIDTH)
 8465                    .border_color(cx.theme().colors().border)
 8466                    .rounded_r_lg()
 8467                    .id("edit_prediction_diff_popover_keybind")
 8468                    .when(!has_keybind, |el| {
 8469                        let status_colors = cx.theme().status();
 8470
 8471                        el.bg(status_colors.error_background)
 8472                            .border_color(status_colors.error.opacity(0.6))
 8473                            .child(Icon::new(IconName::Info).color(Color::Error))
 8474                            .cursor_default()
 8475                            .hoverable_tooltip(move |_window, cx| {
 8476                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8477                            })
 8478                    })
 8479                    .children(keybind),
 8480            )
 8481            .into_any();
 8482
 8483        let longest_row =
 8484            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8485        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8486            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8487        } else {
 8488            layout_line(
 8489                longest_row,
 8490                editor_snapshot,
 8491                style,
 8492                editor_width,
 8493                |_| false,
 8494                window,
 8495                cx,
 8496            )
 8497            .width
 8498        };
 8499
 8500        let viewport_bounds =
 8501            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8502                right: -right_margin,
 8503                ..Default::default()
 8504            });
 8505
 8506        let x_after_longest =
 8507            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8508                - scroll_pixel_position.x;
 8509
 8510        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8511
 8512        // Fully visible if it can be displayed within the window (allow overlapping other
 8513        // panes). However, this is only allowed if the popover starts within text_bounds.
 8514        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8515            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8516
 8517        let mut origin = if can_position_to_the_right {
 8518            point(
 8519                x_after_longest,
 8520                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8521                    - scroll_pixel_position.y,
 8522            )
 8523        } else {
 8524            let cursor_row = newest_selection_head.map(|head| head.row());
 8525            let above_edit = edit_start
 8526                .row()
 8527                .0
 8528                .checked_sub(line_count as u32)
 8529                .map(DisplayRow);
 8530            let below_edit = Some(edit_end.row() + 1);
 8531            let above_cursor =
 8532                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8533            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8534
 8535            // Place the edit popover adjacent to the edit if there is a location
 8536            // available that is onscreen and does not obscure the cursor. Otherwise,
 8537            // place it adjacent to the cursor.
 8538            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8539                .into_iter()
 8540                .flatten()
 8541                .find(|&start_row| {
 8542                    let end_row = start_row + line_count as u32;
 8543                    visible_row_range.contains(&start_row)
 8544                        && visible_row_range.contains(&end_row)
 8545                        && cursor_row.map_or(true, |cursor_row| {
 8546                            !((start_row..end_row).contains(&cursor_row))
 8547                        })
 8548                })?;
 8549
 8550            content_origin
 8551                + point(
 8552                    -scroll_pixel_position.x,
 8553                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8554                )
 8555        };
 8556
 8557        origin.x -= BORDER_WIDTH;
 8558
 8559        window.defer_draw(element, origin, 1);
 8560
 8561        // Do not return an element, since it will already be drawn due to defer_draw.
 8562        None
 8563    }
 8564
 8565    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8566        px(30.)
 8567    }
 8568
 8569    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8570        if self.read_only(cx) {
 8571            cx.theme().players().read_only()
 8572        } else {
 8573            self.style.as_ref().unwrap().local_player
 8574        }
 8575    }
 8576
 8577    fn render_edit_prediction_accept_keybind(
 8578        &self,
 8579        window: &mut Window,
 8580        cx: &App,
 8581    ) -> Option<AnyElement> {
 8582        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8583        let accept_keystroke = accept_binding.keystroke()?;
 8584
 8585        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8586
 8587        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8588            Color::Accent
 8589        } else {
 8590            Color::Muted
 8591        };
 8592
 8593        h_flex()
 8594            .px_0p5()
 8595            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8596            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8597            .text_size(TextSize::XSmall.rems(cx))
 8598            .child(h_flex().children(ui::render_modifiers(
 8599                &accept_keystroke.modifiers,
 8600                PlatformStyle::platform(),
 8601                Some(modifiers_color),
 8602                Some(IconSize::XSmall.rems().into()),
 8603                true,
 8604            )))
 8605            .when(is_platform_style_mac, |parent| {
 8606                parent.child(accept_keystroke.key.clone())
 8607            })
 8608            .when(!is_platform_style_mac, |parent| {
 8609                parent.child(
 8610                    Key::new(
 8611                        util::capitalize(&accept_keystroke.key),
 8612                        Some(Color::Default),
 8613                    )
 8614                    .size(Some(IconSize::XSmall.rems().into())),
 8615                )
 8616            })
 8617            .into_any()
 8618            .into()
 8619    }
 8620
 8621    fn render_edit_prediction_line_popover(
 8622        &self,
 8623        label: impl Into<SharedString>,
 8624        icon: Option<IconName>,
 8625        window: &mut Window,
 8626        cx: &App,
 8627    ) -> Option<Stateful<Div>> {
 8628        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8629
 8630        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8631        let has_keybind = keybind.is_some();
 8632
 8633        let result = h_flex()
 8634            .id("ep-line-popover")
 8635            .py_0p5()
 8636            .pl_1()
 8637            .pr(padding_right)
 8638            .gap_1()
 8639            .rounded_md()
 8640            .border_1()
 8641            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8642            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8643            .shadow_sm()
 8644            .when(!has_keybind, |el| {
 8645                let status_colors = cx.theme().status();
 8646
 8647                el.bg(status_colors.error_background)
 8648                    .border_color(status_colors.error.opacity(0.6))
 8649                    .pl_2()
 8650                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8651                    .cursor_default()
 8652                    .hoverable_tooltip(move |_window, cx| {
 8653                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8654                    })
 8655            })
 8656            .children(keybind)
 8657            .child(
 8658                Label::new(label)
 8659                    .size(LabelSize::Small)
 8660                    .when(!has_keybind, |el| {
 8661                        el.color(cx.theme().status().error.into()).strikethrough()
 8662                    }),
 8663            )
 8664            .when(!has_keybind, |el| {
 8665                el.child(
 8666                    h_flex().ml_1().child(
 8667                        Icon::new(IconName::Info)
 8668                            .size(IconSize::Small)
 8669                            .color(cx.theme().status().error.into()),
 8670                    ),
 8671                )
 8672            })
 8673            .when_some(icon, |element, icon| {
 8674                element.child(
 8675                    div()
 8676                        .mt(px(1.5))
 8677                        .child(Icon::new(icon).size(IconSize::Small)),
 8678                )
 8679            });
 8680
 8681        Some(result)
 8682    }
 8683
 8684    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8685        let accent_color = cx.theme().colors().text_accent;
 8686        let editor_bg_color = cx.theme().colors().editor_background;
 8687        editor_bg_color.blend(accent_color.opacity(0.1))
 8688    }
 8689
 8690    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8691        let accent_color = cx.theme().colors().text_accent;
 8692        let editor_bg_color = cx.theme().colors().editor_background;
 8693        editor_bg_color.blend(accent_color.opacity(0.6))
 8694    }
 8695
 8696    fn render_edit_prediction_cursor_popover(
 8697        &self,
 8698        min_width: Pixels,
 8699        max_width: Pixels,
 8700        cursor_point: Point,
 8701        style: &EditorStyle,
 8702        accept_keystroke: Option<&gpui::Keystroke>,
 8703        _window: &Window,
 8704        cx: &mut Context<Editor>,
 8705    ) -> Option<AnyElement> {
 8706        let provider = self.edit_prediction_provider.as_ref()?;
 8707
 8708        if provider.provider.needs_terms_acceptance(cx) {
 8709            return Some(
 8710                h_flex()
 8711                    .min_w(min_width)
 8712                    .flex_1()
 8713                    .px_2()
 8714                    .py_1()
 8715                    .gap_3()
 8716                    .elevation_2(cx)
 8717                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8718                    .id("accept-terms")
 8719                    .cursor_pointer()
 8720                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8721                    .on_click(cx.listener(|this, _event, window, cx| {
 8722                        cx.stop_propagation();
 8723                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8724                        window.dispatch_action(
 8725                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8726                            cx,
 8727                        );
 8728                    }))
 8729                    .child(
 8730                        h_flex()
 8731                            .flex_1()
 8732                            .gap_2()
 8733                            .child(Icon::new(IconName::ZedPredict))
 8734                            .child(Label::new("Accept Terms of Service"))
 8735                            .child(div().w_full())
 8736                            .child(
 8737                                Icon::new(IconName::ArrowUpRight)
 8738                                    .color(Color::Muted)
 8739                                    .size(IconSize::Small),
 8740                            )
 8741                            .into_any_element(),
 8742                    )
 8743                    .into_any(),
 8744            );
 8745        }
 8746
 8747        let is_refreshing = provider.provider.is_refreshing(cx);
 8748
 8749        fn pending_completion_container() -> Div {
 8750            h_flex()
 8751                .h_full()
 8752                .flex_1()
 8753                .gap_2()
 8754                .child(Icon::new(IconName::ZedPredict))
 8755        }
 8756
 8757        let completion = match &self.active_inline_completion {
 8758            Some(prediction) => {
 8759                if !self.has_visible_completions_menu() {
 8760                    const RADIUS: Pixels = px(6.);
 8761                    const BORDER_WIDTH: Pixels = px(1.);
 8762
 8763                    return Some(
 8764                        h_flex()
 8765                            .elevation_2(cx)
 8766                            .border(BORDER_WIDTH)
 8767                            .border_color(cx.theme().colors().border)
 8768                            .when(accept_keystroke.is_none(), |el| {
 8769                                el.border_color(cx.theme().status().error)
 8770                            })
 8771                            .rounded(RADIUS)
 8772                            .rounded_tl(px(0.))
 8773                            .overflow_hidden()
 8774                            .child(div().px_1p5().child(match &prediction.completion {
 8775                                InlineCompletion::Move { target, snapshot } => {
 8776                                    use text::ToPoint as _;
 8777                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8778                                    {
 8779                                        Icon::new(IconName::ZedPredictDown)
 8780                                    } else {
 8781                                        Icon::new(IconName::ZedPredictUp)
 8782                                    }
 8783                                }
 8784                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8785                            }))
 8786                            .child(
 8787                                h_flex()
 8788                                    .gap_1()
 8789                                    .py_1()
 8790                                    .px_2()
 8791                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8792                                    .border_l_1()
 8793                                    .border_color(cx.theme().colors().border)
 8794                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8795                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8796                                        el.child(
 8797                                            Label::new("Hold")
 8798                                                .size(LabelSize::Small)
 8799                                                .when(accept_keystroke.is_none(), |el| {
 8800                                                    el.strikethrough()
 8801                                                })
 8802                                                .line_height_style(LineHeightStyle::UiLabel),
 8803                                        )
 8804                                    })
 8805                                    .id("edit_prediction_cursor_popover_keybind")
 8806                                    .when(accept_keystroke.is_none(), |el| {
 8807                                        let status_colors = cx.theme().status();
 8808
 8809                                        el.bg(status_colors.error_background)
 8810                                            .border_color(status_colors.error.opacity(0.6))
 8811                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8812                                            .cursor_default()
 8813                                            .hoverable_tooltip(move |_window, cx| {
 8814                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8815                                                    .into()
 8816                                            })
 8817                                    })
 8818                                    .when_some(
 8819                                        accept_keystroke.as_ref(),
 8820                                        |el, accept_keystroke| {
 8821                                            el.child(h_flex().children(ui::render_modifiers(
 8822                                                &accept_keystroke.modifiers,
 8823                                                PlatformStyle::platform(),
 8824                                                Some(Color::Default),
 8825                                                Some(IconSize::XSmall.rems().into()),
 8826                                                false,
 8827                                            )))
 8828                                        },
 8829                                    ),
 8830                            )
 8831                            .into_any(),
 8832                    );
 8833                }
 8834
 8835                self.render_edit_prediction_cursor_popover_preview(
 8836                    prediction,
 8837                    cursor_point,
 8838                    style,
 8839                    cx,
 8840                )?
 8841            }
 8842
 8843            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8844                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8845                    stale_completion,
 8846                    cursor_point,
 8847                    style,
 8848                    cx,
 8849                )?,
 8850
 8851                None => {
 8852                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8853                }
 8854            },
 8855
 8856            None => pending_completion_container().child(Label::new("No Prediction")),
 8857        };
 8858
 8859        let completion = if is_refreshing {
 8860            completion
 8861                .with_animation(
 8862                    "loading-completion",
 8863                    Animation::new(Duration::from_secs(2))
 8864                        .repeat()
 8865                        .with_easing(pulsating_between(0.4, 0.8)),
 8866                    |label, delta| label.opacity(delta),
 8867                )
 8868                .into_any_element()
 8869        } else {
 8870            completion.into_any_element()
 8871        };
 8872
 8873        let has_completion = self.active_inline_completion.is_some();
 8874
 8875        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8876        Some(
 8877            h_flex()
 8878                .min_w(min_width)
 8879                .max_w(max_width)
 8880                .flex_1()
 8881                .elevation_2(cx)
 8882                .border_color(cx.theme().colors().border)
 8883                .child(
 8884                    div()
 8885                        .flex_1()
 8886                        .py_1()
 8887                        .px_2()
 8888                        .overflow_hidden()
 8889                        .child(completion),
 8890                )
 8891                .when_some(accept_keystroke, |el, accept_keystroke| {
 8892                    if !accept_keystroke.modifiers.modified() {
 8893                        return el;
 8894                    }
 8895
 8896                    el.child(
 8897                        h_flex()
 8898                            .h_full()
 8899                            .border_l_1()
 8900                            .rounded_r_lg()
 8901                            .border_color(cx.theme().colors().border)
 8902                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8903                            .gap_1()
 8904                            .py_1()
 8905                            .px_2()
 8906                            .child(
 8907                                h_flex()
 8908                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8909                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8910                                    .child(h_flex().children(ui::render_modifiers(
 8911                                        &accept_keystroke.modifiers,
 8912                                        PlatformStyle::platform(),
 8913                                        Some(if !has_completion {
 8914                                            Color::Muted
 8915                                        } else {
 8916                                            Color::Default
 8917                                        }),
 8918                                        None,
 8919                                        false,
 8920                                    ))),
 8921                            )
 8922                            .child(Label::new("Preview").into_any_element())
 8923                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8924                    )
 8925                })
 8926                .into_any(),
 8927        )
 8928    }
 8929
 8930    fn render_edit_prediction_cursor_popover_preview(
 8931        &self,
 8932        completion: &InlineCompletionState,
 8933        cursor_point: Point,
 8934        style: &EditorStyle,
 8935        cx: &mut Context<Editor>,
 8936    ) -> Option<Div> {
 8937        use text::ToPoint as _;
 8938
 8939        fn render_relative_row_jump(
 8940            prefix: impl Into<String>,
 8941            current_row: u32,
 8942            target_row: u32,
 8943        ) -> Div {
 8944            let (row_diff, arrow) = if target_row < current_row {
 8945                (current_row - target_row, IconName::ArrowUp)
 8946            } else {
 8947                (target_row - current_row, IconName::ArrowDown)
 8948            };
 8949
 8950            h_flex()
 8951                .child(
 8952                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8953                        .color(Color::Muted)
 8954                        .size(LabelSize::Small),
 8955                )
 8956                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8957        }
 8958
 8959        match &completion.completion {
 8960            InlineCompletion::Move {
 8961                target, snapshot, ..
 8962            } => Some(
 8963                h_flex()
 8964                    .px_2()
 8965                    .gap_2()
 8966                    .flex_1()
 8967                    .child(
 8968                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8969                            Icon::new(IconName::ZedPredictDown)
 8970                        } else {
 8971                            Icon::new(IconName::ZedPredictUp)
 8972                        },
 8973                    )
 8974                    .child(Label::new("Jump to Edit")),
 8975            ),
 8976
 8977            InlineCompletion::Edit {
 8978                edits,
 8979                edit_preview,
 8980                snapshot,
 8981                display_mode: _,
 8982            } => {
 8983                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8984
 8985                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8986                    &snapshot,
 8987                    &edits,
 8988                    edit_preview.as_ref()?,
 8989                    true,
 8990                    cx,
 8991                )
 8992                .first_line_preview();
 8993
 8994                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8995                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8996
 8997                let preview = h_flex()
 8998                    .gap_1()
 8999                    .min_w_16()
 9000                    .child(styled_text)
 9001                    .when(has_more_lines, |parent| parent.child(""));
 9002
 9003                let left = if first_edit_row != cursor_point.row {
 9004                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9005                        .into_any_element()
 9006                } else {
 9007                    Icon::new(IconName::ZedPredict).into_any_element()
 9008                };
 9009
 9010                Some(
 9011                    h_flex()
 9012                        .h_full()
 9013                        .flex_1()
 9014                        .gap_2()
 9015                        .pr_1()
 9016                        .overflow_x_hidden()
 9017                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9018                        .child(left)
 9019                        .child(preview),
 9020                )
 9021            }
 9022        }
 9023    }
 9024
 9025    pub fn render_context_menu(
 9026        &self,
 9027        style: &EditorStyle,
 9028        max_height_in_lines: u32,
 9029        window: &mut Window,
 9030        cx: &mut Context<Editor>,
 9031    ) -> Option<AnyElement> {
 9032        let menu = self.context_menu.borrow();
 9033        let menu = menu.as_ref()?;
 9034        if !menu.visible() {
 9035            return None;
 9036        };
 9037        Some(menu.render(style, max_height_in_lines, window, cx))
 9038    }
 9039
 9040    fn render_context_menu_aside(
 9041        &mut self,
 9042        max_size: Size<Pixels>,
 9043        window: &mut Window,
 9044        cx: &mut Context<Editor>,
 9045    ) -> Option<AnyElement> {
 9046        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9047            if menu.visible() {
 9048                menu.render_aside(max_size, window, cx)
 9049            } else {
 9050                None
 9051            }
 9052        })
 9053    }
 9054
 9055    fn hide_context_menu(
 9056        &mut self,
 9057        window: &mut Window,
 9058        cx: &mut Context<Self>,
 9059    ) -> Option<CodeContextMenu> {
 9060        cx.notify();
 9061        self.completion_tasks.clear();
 9062        let context_menu = self.context_menu.borrow_mut().take();
 9063        self.stale_inline_completion_in_menu.take();
 9064        self.update_visible_inline_completion(window, cx);
 9065        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9066            if let Some(completion_provider) = &self.completion_provider {
 9067                completion_provider.selection_changed(None, window, cx);
 9068            }
 9069        }
 9070        context_menu
 9071    }
 9072
 9073    fn show_snippet_choices(
 9074        &mut self,
 9075        choices: &Vec<String>,
 9076        selection: Range<Anchor>,
 9077        cx: &mut Context<Self>,
 9078    ) {
 9079        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9080            (Some(a), Some(b)) if a == b => a,
 9081            _ => {
 9082                log::error!("expected anchor range to have matching buffer IDs");
 9083                return;
 9084            }
 9085        };
 9086        let multi_buffer = self.buffer().read(cx);
 9087        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9088            return;
 9089        };
 9090
 9091        let id = post_inc(&mut self.next_completion_id);
 9092        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9093        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9094            CompletionsMenu::new_snippet_choices(
 9095                id,
 9096                true,
 9097                choices,
 9098                selection,
 9099                buffer,
 9100                snippet_sort_order,
 9101            ),
 9102        ));
 9103    }
 9104
 9105    pub fn insert_snippet(
 9106        &mut self,
 9107        insertion_ranges: &[Range<usize>],
 9108        snippet: Snippet,
 9109        window: &mut Window,
 9110        cx: &mut Context<Self>,
 9111    ) -> Result<()> {
 9112        struct Tabstop<T> {
 9113            is_end_tabstop: bool,
 9114            ranges: Vec<Range<T>>,
 9115            choices: Option<Vec<String>>,
 9116        }
 9117
 9118        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9119            let snippet_text: Arc<str> = snippet.text.clone().into();
 9120            let edits = insertion_ranges
 9121                .iter()
 9122                .cloned()
 9123                .map(|range| (range, snippet_text.clone()));
 9124            let autoindent_mode = AutoindentMode::Block {
 9125                original_indent_columns: Vec::new(),
 9126            };
 9127            buffer.edit(edits, Some(autoindent_mode), cx);
 9128
 9129            let snapshot = &*buffer.read(cx);
 9130            let snippet = &snippet;
 9131            snippet
 9132                .tabstops
 9133                .iter()
 9134                .map(|tabstop| {
 9135                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9136                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9137                    });
 9138                    let mut tabstop_ranges = tabstop
 9139                        .ranges
 9140                        .iter()
 9141                        .flat_map(|tabstop_range| {
 9142                            let mut delta = 0_isize;
 9143                            insertion_ranges.iter().map(move |insertion_range| {
 9144                                let insertion_start = insertion_range.start as isize + delta;
 9145                                delta +=
 9146                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9147
 9148                                let start = ((insertion_start + tabstop_range.start) as usize)
 9149                                    .min(snapshot.len());
 9150                                let end = ((insertion_start + tabstop_range.end) as usize)
 9151                                    .min(snapshot.len());
 9152                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9153                            })
 9154                        })
 9155                        .collect::<Vec<_>>();
 9156                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9157
 9158                    Tabstop {
 9159                        is_end_tabstop,
 9160                        ranges: tabstop_ranges,
 9161                        choices: tabstop.choices.clone(),
 9162                    }
 9163                })
 9164                .collect::<Vec<_>>()
 9165        });
 9166        if let Some(tabstop) = tabstops.first() {
 9167            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9168                // Reverse order so that the first range is the newest created selection.
 9169                // Completions will use it and autoscroll will prioritize it.
 9170                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9171            });
 9172
 9173            if let Some(choices) = &tabstop.choices {
 9174                if let Some(selection) = tabstop.ranges.first() {
 9175                    self.show_snippet_choices(choices, selection.clone(), cx)
 9176                }
 9177            }
 9178
 9179            // If we're already at the last tabstop and it's at the end of the snippet,
 9180            // we're done, we don't need to keep the state around.
 9181            if !tabstop.is_end_tabstop {
 9182                let choices = tabstops
 9183                    .iter()
 9184                    .map(|tabstop| tabstop.choices.clone())
 9185                    .collect();
 9186
 9187                let ranges = tabstops
 9188                    .into_iter()
 9189                    .map(|tabstop| tabstop.ranges)
 9190                    .collect::<Vec<_>>();
 9191
 9192                self.snippet_stack.push(SnippetState {
 9193                    active_index: 0,
 9194                    ranges,
 9195                    choices,
 9196                });
 9197            }
 9198
 9199            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9200            if self.autoclose_regions.is_empty() {
 9201                let snapshot = self.buffer.read(cx).snapshot(cx);
 9202                for selection in &mut self.selections.all::<Point>(cx) {
 9203                    let selection_head = selection.head();
 9204                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9205                        continue;
 9206                    };
 9207
 9208                    let mut bracket_pair = None;
 9209                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9210                    let prev_chars = snapshot
 9211                        .reversed_chars_at(selection_head)
 9212                        .collect::<String>();
 9213                    for (pair, enabled) in scope.brackets() {
 9214                        if enabled
 9215                            && pair.close
 9216                            && prev_chars.starts_with(pair.start.as_str())
 9217                            && next_chars.starts_with(pair.end.as_str())
 9218                        {
 9219                            bracket_pair = Some(pair.clone());
 9220                            break;
 9221                        }
 9222                    }
 9223                    if let Some(pair) = bracket_pair {
 9224                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9225                        let autoclose_enabled =
 9226                            self.use_autoclose && snapshot_settings.use_autoclose;
 9227                        if autoclose_enabled {
 9228                            let start = snapshot.anchor_after(selection_head);
 9229                            let end = snapshot.anchor_after(selection_head);
 9230                            self.autoclose_regions.push(AutocloseRegion {
 9231                                selection_id: selection.id,
 9232                                range: start..end,
 9233                                pair,
 9234                            });
 9235                        }
 9236                    }
 9237                }
 9238            }
 9239        }
 9240        Ok(())
 9241    }
 9242
 9243    pub fn move_to_next_snippet_tabstop(
 9244        &mut self,
 9245        window: &mut Window,
 9246        cx: &mut Context<Self>,
 9247    ) -> bool {
 9248        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9249    }
 9250
 9251    pub fn move_to_prev_snippet_tabstop(
 9252        &mut self,
 9253        window: &mut Window,
 9254        cx: &mut Context<Self>,
 9255    ) -> bool {
 9256        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9257    }
 9258
 9259    pub fn move_to_snippet_tabstop(
 9260        &mut self,
 9261        bias: Bias,
 9262        window: &mut Window,
 9263        cx: &mut Context<Self>,
 9264    ) -> bool {
 9265        if let Some(mut snippet) = self.snippet_stack.pop() {
 9266            match bias {
 9267                Bias::Left => {
 9268                    if snippet.active_index > 0 {
 9269                        snippet.active_index -= 1;
 9270                    } else {
 9271                        self.snippet_stack.push(snippet);
 9272                        return false;
 9273                    }
 9274                }
 9275                Bias::Right => {
 9276                    if snippet.active_index + 1 < snippet.ranges.len() {
 9277                        snippet.active_index += 1;
 9278                    } else {
 9279                        self.snippet_stack.push(snippet);
 9280                        return false;
 9281                    }
 9282                }
 9283            }
 9284            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9285                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9286                    // Reverse order so that the first range is the newest created selection.
 9287                    // Completions will use it and autoscroll will prioritize it.
 9288                    s.select_ranges(current_ranges.iter().rev().cloned())
 9289                });
 9290
 9291                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9292                    if let Some(selection) = current_ranges.first() {
 9293                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9294                    }
 9295                }
 9296
 9297                // If snippet state is not at the last tabstop, push it back on the stack
 9298                if snippet.active_index + 1 < snippet.ranges.len() {
 9299                    self.snippet_stack.push(snippet);
 9300                }
 9301                return true;
 9302            }
 9303        }
 9304
 9305        false
 9306    }
 9307
 9308    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9309        self.transact(window, cx, |this, window, cx| {
 9310            this.select_all(&SelectAll, window, cx);
 9311            this.insert("", window, cx);
 9312        });
 9313    }
 9314
 9315    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9316        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9317        self.transact(window, cx, |this, window, cx| {
 9318            this.select_autoclose_pair(window, cx);
 9319            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9320            if !this.linked_edit_ranges.is_empty() {
 9321                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9322                let snapshot = this.buffer.read(cx).snapshot(cx);
 9323
 9324                for selection in selections.iter() {
 9325                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9326                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9327                    if selection_start.buffer_id != selection_end.buffer_id {
 9328                        continue;
 9329                    }
 9330                    if let Some(ranges) =
 9331                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9332                    {
 9333                        for (buffer, entries) in ranges {
 9334                            linked_ranges.entry(buffer).or_default().extend(entries);
 9335                        }
 9336                    }
 9337                }
 9338            }
 9339
 9340            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9341            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9342            for selection in &mut selections {
 9343                if selection.is_empty() {
 9344                    let old_head = selection.head();
 9345                    let mut new_head =
 9346                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9347                            .to_point(&display_map);
 9348                    if let Some((buffer, line_buffer_range)) = display_map
 9349                        .buffer_snapshot
 9350                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9351                    {
 9352                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9353                        let indent_len = match indent_size.kind {
 9354                            IndentKind::Space => {
 9355                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9356                            }
 9357                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9358                        };
 9359                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9360                            let indent_len = indent_len.get();
 9361                            new_head = cmp::min(
 9362                                new_head,
 9363                                MultiBufferPoint::new(
 9364                                    old_head.row,
 9365                                    ((old_head.column - 1) / indent_len) * indent_len,
 9366                                ),
 9367                            );
 9368                        }
 9369                    }
 9370
 9371                    selection.set_head(new_head, SelectionGoal::None);
 9372                }
 9373            }
 9374
 9375            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9376                s.select(selections)
 9377            });
 9378            this.insert("", window, cx);
 9379            let empty_str: Arc<str> = Arc::from("");
 9380            for (buffer, edits) in linked_ranges {
 9381                let snapshot = buffer.read(cx).snapshot();
 9382                use text::ToPoint as TP;
 9383
 9384                let edits = edits
 9385                    .into_iter()
 9386                    .map(|range| {
 9387                        let end_point = TP::to_point(&range.end, &snapshot);
 9388                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9389
 9390                        if end_point == start_point {
 9391                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9392                                .saturating_sub(1);
 9393                            start_point =
 9394                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9395                        };
 9396
 9397                        (start_point..end_point, empty_str.clone())
 9398                    })
 9399                    .sorted_by_key(|(range, _)| range.start)
 9400                    .collect::<Vec<_>>();
 9401                buffer.update(cx, |this, cx| {
 9402                    this.edit(edits, None, cx);
 9403                })
 9404            }
 9405            this.refresh_inline_completion(true, false, window, cx);
 9406            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9407        });
 9408    }
 9409
 9410    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9411        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9412        self.transact(window, cx, |this, window, cx| {
 9413            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9414                s.move_with(|map, selection| {
 9415                    if selection.is_empty() {
 9416                        let cursor = movement::right(map, selection.head());
 9417                        selection.end = cursor;
 9418                        selection.reversed = true;
 9419                        selection.goal = SelectionGoal::None;
 9420                    }
 9421                })
 9422            });
 9423            this.insert("", window, cx);
 9424            this.refresh_inline_completion(true, false, window, cx);
 9425        });
 9426    }
 9427
 9428    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9429        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9430        if self.move_to_prev_snippet_tabstop(window, cx) {
 9431            return;
 9432        }
 9433        self.outdent(&Outdent, window, cx);
 9434    }
 9435
 9436    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9437        if self.move_to_next_snippet_tabstop(window, cx) {
 9438            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9439            return;
 9440        }
 9441        if self.read_only(cx) {
 9442            return;
 9443        }
 9444        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9445        let mut selections = self.selections.all_adjusted(cx);
 9446        let buffer = self.buffer.read(cx);
 9447        let snapshot = buffer.snapshot(cx);
 9448        let rows_iter = selections.iter().map(|s| s.head().row);
 9449        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9450
 9451        let has_some_cursor_in_whitespace = selections
 9452            .iter()
 9453            .filter(|selection| selection.is_empty())
 9454            .any(|selection| {
 9455                let cursor = selection.head();
 9456                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9457                cursor.column < current_indent.len
 9458            });
 9459
 9460        let mut edits = Vec::new();
 9461        let mut prev_edited_row = 0;
 9462        let mut row_delta = 0;
 9463        for selection in &mut selections {
 9464            if selection.start.row != prev_edited_row {
 9465                row_delta = 0;
 9466            }
 9467            prev_edited_row = selection.end.row;
 9468
 9469            // If the selection is non-empty, then increase the indentation of the selected lines.
 9470            if !selection.is_empty() {
 9471                row_delta =
 9472                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9473                continue;
 9474            }
 9475
 9476            let cursor = selection.head();
 9477            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9478            if let Some(suggested_indent) =
 9479                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9480            {
 9481                // Don't do anything if already at suggested indent
 9482                // and there is any other cursor which is not
 9483                if has_some_cursor_in_whitespace
 9484                    && cursor.column == current_indent.len
 9485                    && current_indent.len == suggested_indent.len
 9486                {
 9487                    continue;
 9488                }
 9489
 9490                // Adjust line and move cursor to suggested indent
 9491                // if cursor is not at suggested indent
 9492                if cursor.column < suggested_indent.len
 9493                    && cursor.column <= current_indent.len
 9494                    && current_indent.len <= suggested_indent.len
 9495                {
 9496                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9497                    selection.end = selection.start;
 9498                    if row_delta == 0 {
 9499                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9500                            cursor.row,
 9501                            current_indent,
 9502                            suggested_indent,
 9503                        ));
 9504                        row_delta = suggested_indent.len - current_indent.len;
 9505                    }
 9506                    continue;
 9507                }
 9508
 9509                // If current indent is more than suggested indent
 9510                // only move cursor to current indent and skip indent
 9511                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9512                    selection.start = Point::new(cursor.row, current_indent.len);
 9513                    selection.end = selection.start;
 9514                    continue;
 9515                }
 9516            }
 9517
 9518            // Otherwise, insert a hard or soft tab.
 9519            let settings = buffer.language_settings_at(cursor, cx);
 9520            let tab_size = if settings.hard_tabs {
 9521                IndentSize::tab()
 9522            } else {
 9523                let tab_size = settings.tab_size.get();
 9524                let indent_remainder = snapshot
 9525                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9526                    .flat_map(str::chars)
 9527                    .fold(row_delta % tab_size, |counter: u32, c| {
 9528                        if c == '\t' {
 9529                            0
 9530                        } else {
 9531                            (counter + 1) % tab_size
 9532                        }
 9533                    });
 9534
 9535                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9536                IndentSize::spaces(chars_to_next_tab_stop)
 9537            };
 9538            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9539            selection.end = selection.start;
 9540            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9541            row_delta += tab_size.len;
 9542        }
 9543
 9544        self.transact(window, cx, |this, window, cx| {
 9545            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9546            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9547                s.select(selections)
 9548            });
 9549            this.refresh_inline_completion(true, false, window, cx);
 9550        });
 9551    }
 9552
 9553    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9554        if self.read_only(cx) {
 9555            return;
 9556        }
 9557        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9558        let mut selections = self.selections.all::<Point>(cx);
 9559        let mut prev_edited_row = 0;
 9560        let mut row_delta = 0;
 9561        let mut edits = Vec::new();
 9562        let buffer = self.buffer.read(cx);
 9563        let snapshot = buffer.snapshot(cx);
 9564        for selection in &mut selections {
 9565            if selection.start.row != prev_edited_row {
 9566                row_delta = 0;
 9567            }
 9568            prev_edited_row = selection.end.row;
 9569
 9570            row_delta =
 9571                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9572        }
 9573
 9574        self.transact(window, cx, |this, window, cx| {
 9575            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9576            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9577                s.select(selections)
 9578            });
 9579        });
 9580    }
 9581
 9582    fn indent_selection(
 9583        buffer: &MultiBuffer,
 9584        snapshot: &MultiBufferSnapshot,
 9585        selection: &mut Selection<Point>,
 9586        edits: &mut Vec<(Range<Point>, String)>,
 9587        delta_for_start_row: u32,
 9588        cx: &App,
 9589    ) -> u32 {
 9590        let settings = buffer.language_settings_at(selection.start, cx);
 9591        let tab_size = settings.tab_size.get();
 9592        let indent_kind = if settings.hard_tabs {
 9593            IndentKind::Tab
 9594        } else {
 9595            IndentKind::Space
 9596        };
 9597        let mut start_row = selection.start.row;
 9598        let mut end_row = selection.end.row + 1;
 9599
 9600        // If a selection ends at the beginning of a line, don't indent
 9601        // that last line.
 9602        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9603            end_row -= 1;
 9604        }
 9605
 9606        // Avoid re-indenting a row that has already been indented by a
 9607        // previous selection, but still update this selection's column
 9608        // to reflect that indentation.
 9609        if delta_for_start_row > 0 {
 9610            start_row += 1;
 9611            selection.start.column += delta_for_start_row;
 9612            if selection.end.row == selection.start.row {
 9613                selection.end.column += delta_for_start_row;
 9614            }
 9615        }
 9616
 9617        let mut delta_for_end_row = 0;
 9618        let has_multiple_rows = start_row + 1 != end_row;
 9619        for row in start_row..end_row {
 9620            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9621            let indent_delta = match (current_indent.kind, indent_kind) {
 9622                (IndentKind::Space, IndentKind::Space) => {
 9623                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9624                    IndentSize::spaces(columns_to_next_tab_stop)
 9625                }
 9626                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9627                (_, IndentKind::Tab) => IndentSize::tab(),
 9628            };
 9629
 9630            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9631                0
 9632            } else {
 9633                selection.start.column
 9634            };
 9635            let row_start = Point::new(row, start);
 9636            edits.push((
 9637                row_start..row_start,
 9638                indent_delta.chars().collect::<String>(),
 9639            ));
 9640
 9641            // Update this selection's endpoints to reflect the indentation.
 9642            if row == selection.start.row {
 9643                selection.start.column += indent_delta.len;
 9644            }
 9645            if row == selection.end.row {
 9646                selection.end.column += indent_delta.len;
 9647                delta_for_end_row = indent_delta.len;
 9648            }
 9649        }
 9650
 9651        if selection.start.row == selection.end.row {
 9652            delta_for_start_row + delta_for_end_row
 9653        } else {
 9654            delta_for_end_row
 9655        }
 9656    }
 9657
 9658    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9659        if self.read_only(cx) {
 9660            return;
 9661        }
 9662        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9663        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9664        let selections = self.selections.all::<Point>(cx);
 9665        let mut deletion_ranges = Vec::new();
 9666        let mut last_outdent = None;
 9667        {
 9668            let buffer = self.buffer.read(cx);
 9669            let snapshot = buffer.snapshot(cx);
 9670            for selection in &selections {
 9671                let settings = buffer.language_settings_at(selection.start, cx);
 9672                let tab_size = settings.tab_size.get();
 9673                let mut rows = selection.spanned_rows(false, &display_map);
 9674
 9675                // Avoid re-outdenting a row that has already been outdented by a
 9676                // previous selection.
 9677                if let Some(last_row) = last_outdent {
 9678                    if last_row == rows.start {
 9679                        rows.start = rows.start.next_row();
 9680                    }
 9681                }
 9682                let has_multiple_rows = rows.len() > 1;
 9683                for row in rows.iter_rows() {
 9684                    let indent_size = snapshot.indent_size_for_line(row);
 9685                    if indent_size.len > 0 {
 9686                        let deletion_len = match indent_size.kind {
 9687                            IndentKind::Space => {
 9688                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9689                                if columns_to_prev_tab_stop == 0 {
 9690                                    tab_size
 9691                                } else {
 9692                                    columns_to_prev_tab_stop
 9693                                }
 9694                            }
 9695                            IndentKind::Tab => 1,
 9696                        };
 9697                        let start = if has_multiple_rows
 9698                            || deletion_len > selection.start.column
 9699                            || indent_size.len < selection.start.column
 9700                        {
 9701                            0
 9702                        } else {
 9703                            selection.start.column - deletion_len
 9704                        };
 9705                        deletion_ranges.push(
 9706                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9707                        );
 9708                        last_outdent = Some(row);
 9709                    }
 9710                }
 9711            }
 9712        }
 9713
 9714        self.transact(window, cx, |this, window, cx| {
 9715            this.buffer.update(cx, |buffer, cx| {
 9716                let empty_str: Arc<str> = Arc::default();
 9717                buffer.edit(
 9718                    deletion_ranges
 9719                        .into_iter()
 9720                        .map(|range| (range, empty_str.clone())),
 9721                    None,
 9722                    cx,
 9723                );
 9724            });
 9725            let selections = this.selections.all::<usize>(cx);
 9726            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9727                s.select(selections)
 9728            });
 9729        });
 9730    }
 9731
 9732    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9733        if self.read_only(cx) {
 9734            return;
 9735        }
 9736        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9737        let selections = self
 9738            .selections
 9739            .all::<usize>(cx)
 9740            .into_iter()
 9741            .map(|s| s.range());
 9742
 9743        self.transact(window, cx, |this, window, cx| {
 9744            this.buffer.update(cx, |buffer, cx| {
 9745                buffer.autoindent_ranges(selections, cx);
 9746            });
 9747            let selections = this.selections.all::<usize>(cx);
 9748            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9749                s.select(selections)
 9750            });
 9751        });
 9752    }
 9753
 9754    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9755        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9756        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9757        let selections = self.selections.all::<Point>(cx);
 9758
 9759        let mut new_cursors = Vec::new();
 9760        let mut edit_ranges = Vec::new();
 9761        let mut selections = selections.iter().peekable();
 9762        while let Some(selection) = selections.next() {
 9763            let mut rows = selection.spanned_rows(false, &display_map);
 9764            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9765
 9766            // Accumulate contiguous regions of rows that we want to delete.
 9767            while let Some(next_selection) = selections.peek() {
 9768                let next_rows = next_selection.spanned_rows(false, &display_map);
 9769                if next_rows.start <= rows.end {
 9770                    rows.end = next_rows.end;
 9771                    selections.next().unwrap();
 9772                } else {
 9773                    break;
 9774                }
 9775            }
 9776
 9777            let buffer = &display_map.buffer_snapshot;
 9778            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9779            let edit_end;
 9780            let cursor_buffer_row;
 9781            if buffer.max_point().row >= rows.end.0 {
 9782                // If there's a line after the range, delete the \n from the end of the row range
 9783                // and position the cursor on the next line.
 9784                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9785                cursor_buffer_row = rows.end;
 9786            } else {
 9787                // If there isn't a line after the range, delete the \n from the line before the
 9788                // start of the row range and position the cursor there.
 9789                edit_start = edit_start.saturating_sub(1);
 9790                edit_end = buffer.len();
 9791                cursor_buffer_row = rows.start.previous_row();
 9792            }
 9793
 9794            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9795            *cursor.column_mut() =
 9796                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9797
 9798            new_cursors.push((
 9799                selection.id,
 9800                buffer.anchor_after(cursor.to_point(&display_map)),
 9801            ));
 9802            edit_ranges.push(edit_start..edit_end);
 9803        }
 9804
 9805        self.transact(window, cx, |this, window, cx| {
 9806            let buffer = this.buffer.update(cx, |buffer, cx| {
 9807                let empty_str: Arc<str> = Arc::default();
 9808                buffer.edit(
 9809                    edit_ranges
 9810                        .into_iter()
 9811                        .map(|range| (range, empty_str.clone())),
 9812                    None,
 9813                    cx,
 9814                );
 9815                buffer.snapshot(cx)
 9816            });
 9817            let new_selections = new_cursors
 9818                .into_iter()
 9819                .map(|(id, cursor)| {
 9820                    let cursor = cursor.to_point(&buffer);
 9821                    Selection {
 9822                        id,
 9823                        start: cursor,
 9824                        end: cursor,
 9825                        reversed: false,
 9826                        goal: SelectionGoal::None,
 9827                    }
 9828                })
 9829                .collect();
 9830
 9831            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9832                s.select(new_selections);
 9833            });
 9834        });
 9835    }
 9836
 9837    pub fn join_lines_impl(
 9838        &mut self,
 9839        insert_whitespace: bool,
 9840        window: &mut Window,
 9841        cx: &mut Context<Self>,
 9842    ) {
 9843        if self.read_only(cx) {
 9844            return;
 9845        }
 9846        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9847        for selection in self.selections.all::<Point>(cx) {
 9848            let start = MultiBufferRow(selection.start.row);
 9849            // Treat single line selections as if they include the next line. Otherwise this action
 9850            // would do nothing for single line selections individual cursors.
 9851            let end = if selection.start.row == selection.end.row {
 9852                MultiBufferRow(selection.start.row + 1)
 9853            } else {
 9854                MultiBufferRow(selection.end.row)
 9855            };
 9856
 9857            if let Some(last_row_range) = row_ranges.last_mut() {
 9858                if start <= last_row_range.end {
 9859                    last_row_range.end = end;
 9860                    continue;
 9861                }
 9862            }
 9863            row_ranges.push(start..end);
 9864        }
 9865
 9866        let snapshot = self.buffer.read(cx).snapshot(cx);
 9867        let mut cursor_positions = Vec::new();
 9868        for row_range in &row_ranges {
 9869            let anchor = snapshot.anchor_before(Point::new(
 9870                row_range.end.previous_row().0,
 9871                snapshot.line_len(row_range.end.previous_row()),
 9872            ));
 9873            cursor_positions.push(anchor..anchor);
 9874        }
 9875
 9876        self.transact(window, cx, |this, window, cx| {
 9877            for row_range in row_ranges.into_iter().rev() {
 9878                for row in row_range.iter_rows().rev() {
 9879                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9880                    let next_line_row = row.next_row();
 9881                    let indent = snapshot.indent_size_for_line(next_line_row);
 9882                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9883
 9884                    let replace =
 9885                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9886                            " "
 9887                        } else {
 9888                            ""
 9889                        };
 9890
 9891                    this.buffer.update(cx, |buffer, cx| {
 9892                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9893                    });
 9894                }
 9895            }
 9896
 9897            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9898                s.select_anchor_ranges(cursor_positions)
 9899            });
 9900        });
 9901    }
 9902
 9903    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9904        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9905        self.join_lines_impl(true, window, cx);
 9906    }
 9907
 9908    pub fn sort_lines_case_sensitive(
 9909        &mut self,
 9910        _: &SortLinesCaseSensitive,
 9911        window: &mut Window,
 9912        cx: &mut Context<Self>,
 9913    ) {
 9914        self.manipulate_lines(window, cx, |lines| lines.sort())
 9915    }
 9916
 9917    pub fn sort_lines_case_insensitive(
 9918        &mut self,
 9919        _: &SortLinesCaseInsensitive,
 9920        window: &mut Window,
 9921        cx: &mut Context<Self>,
 9922    ) {
 9923        self.manipulate_lines(window, cx, |lines| {
 9924            lines.sort_by_key(|line| line.to_lowercase())
 9925        })
 9926    }
 9927
 9928    pub fn unique_lines_case_insensitive(
 9929        &mut self,
 9930        _: &UniqueLinesCaseInsensitive,
 9931        window: &mut Window,
 9932        cx: &mut Context<Self>,
 9933    ) {
 9934        self.manipulate_lines(window, cx, |lines| {
 9935            let mut seen = HashSet::default();
 9936            lines.retain(|line| seen.insert(line.to_lowercase()));
 9937        })
 9938    }
 9939
 9940    pub fn unique_lines_case_sensitive(
 9941        &mut self,
 9942        _: &UniqueLinesCaseSensitive,
 9943        window: &mut Window,
 9944        cx: &mut Context<Self>,
 9945    ) {
 9946        self.manipulate_lines(window, cx, |lines| {
 9947            let mut seen = HashSet::default();
 9948            lines.retain(|line| seen.insert(*line));
 9949        })
 9950    }
 9951
 9952    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9953        let Some(project) = self.project.clone() else {
 9954            return;
 9955        };
 9956        self.reload(project, window, cx)
 9957            .detach_and_notify_err(window, cx);
 9958    }
 9959
 9960    pub fn restore_file(
 9961        &mut self,
 9962        _: &::git::RestoreFile,
 9963        window: &mut Window,
 9964        cx: &mut Context<Self>,
 9965    ) {
 9966        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9967        let mut buffer_ids = HashSet::default();
 9968        let snapshot = self.buffer().read(cx).snapshot(cx);
 9969        for selection in self.selections.all::<usize>(cx) {
 9970            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9971        }
 9972
 9973        let buffer = self.buffer().read(cx);
 9974        let ranges = buffer_ids
 9975            .into_iter()
 9976            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9977            .collect::<Vec<_>>();
 9978
 9979        self.restore_hunks_in_ranges(ranges, window, cx);
 9980    }
 9981
 9982    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9983        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9984        let selections = self
 9985            .selections
 9986            .all(cx)
 9987            .into_iter()
 9988            .map(|s| s.range())
 9989            .collect();
 9990        self.restore_hunks_in_ranges(selections, window, cx);
 9991    }
 9992
 9993    pub fn restore_hunks_in_ranges(
 9994        &mut self,
 9995        ranges: Vec<Range<Point>>,
 9996        window: &mut Window,
 9997        cx: &mut Context<Editor>,
 9998    ) {
 9999        let mut revert_changes = HashMap::default();
10000        let chunk_by = self
10001            .snapshot(window, cx)
10002            .hunks_for_ranges(ranges)
10003            .into_iter()
10004            .chunk_by(|hunk| hunk.buffer_id);
10005        for (buffer_id, hunks) in &chunk_by {
10006            let hunks = hunks.collect::<Vec<_>>();
10007            for hunk in &hunks {
10008                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10009            }
10010            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10011        }
10012        drop(chunk_by);
10013        if !revert_changes.is_empty() {
10014            self.transact(window, cx, |editor, window, cx| {
10015                editor.restore(revert_changes, window, cx);
10016            });
10017        }
10018    }
10019
10020    pub fn open_active_item_in_terminal(
10021        &mut self,
10022        _: &OpenInTerminal,
10023        window: &mut Window,
10024        cx: &mut Context<Self>,
10025    ) {
10026        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10027            let project_path = buffer.read(cx).project_path(cx)?;
10028            let project = self.project.as_ref()?.read(cx);
10029            let entry = project.entry_for_path(&project_path, cx)?;
10030            let parent = match &entry.canonical_path {
10031                Some(canonical_path) => canonical_path.to_path_buf(),
10032                None => project.absolute_path(&project_path, cx)?,
10033            }
10034            .parent()?
10035            .to_path_buf();
10036            Some(parent)
10037        }) {
10038            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10039        }
10040    }
10041
10042    fn set_breakpoint_context_menu(
10043        &mut self,
10044        display_row: DisplayRow,
10045        position: Option<Anchor>,
10046        clicked_point: gpui::Point<Pixels>,
10047        window: &mut Window,
10048        cx: &mut Context<Self>,
10049    ) {
10050        if !cx.has_flag::<DebuggerFeatureFlag>() {
10051            return;
10052        }
10053        let source = self
10054            .buffer
10055            .read(cx)
10056            .snapshot(cx)
10057            .anchor_before(Point::new(display_row.0, 0u32));
10058
10059        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10060
10061        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10062            self,
10063            source,
10064            clicked_point,
10065            context_menu,
10066            window,
10067            cx,
10068        );
10069    }
10070
10071    fn add_edit_breakpoint_block(
10072        &mut self,
10073        anchor: Anchor,
10074        breakpoint: &Breakpoint,
10075        edit_action: BreakpointPromptEditAction,
10076        window: &mut Window,
10077        cx: &mut Context<Self>,
10078    ) {
10079        let weak_editor = cx.weak_entity();
10080        let bp_prompt = cx.new(|cx| {
10081            BreakpointPromptEditor::new(
10082                weak_editor,
10083                anchor,
10084                breakpoint.clone(),
10085                edit_action,
10086                window,
10087                cx,
10088            )
10089        });
10090
10091        let height = bp_prompt.update(cx, |this, cx| {
10092            this.prompt
10093                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10094        });
10095        let cloned_prompt = bp_prompt.clone();
10096        let blocks = vec![BlockProperties {
10097            style: BlockStyle::Sticky,
10098            placement: BlockPlacement::Above(anchor),
10099            height: Some(height),
10100            render: Arc::new(move |cx| {
10101                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10102                cloned_prompt.clone().into_any_element()
10103            }),
10104            priority: 0,
10105            render_in_minimap: true,
10106        }];
10107
10108        let focus_handle = bp_prompt.focus_handle(cx);
10109        window.focus(&focus_handle);
10110
10111        let block_ids = self.insert_blocks(blocks, None, cx);
10112        bp_prompt.update(cx, |prompt, _| {
10113            prompt.add_block_ids(block_ids);
10114        });
10115    }
10116
10117    pub(crate) fn breakpoint_at_row(
10118        &self,
10119        row: u32,
10120        window: &mut Window,
10121        cx: &mut Context<Self>,
10122    ) -> Option<(Anchor, Breakpoint)> {
10123        let snapshot = self.snapshot(window, cx);
10124        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10125
10126        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10127    }
10128
10129    pub(crate) fn breakpoint_at_anchor(
10130        &self,
10131        breakpoint_position: Anchor,
10132        snapshot: &EditorSnapshot,
10133        cx: &mut Context<Self>,
10134    ) -> Option<(Anchor, Breakpoint)> {
10135        let project = self.project.clone()?;
10136
10137        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10138            snapshot
10139                .buffer_snapshot
10140                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10141        })?;
10142
10143        let enclosing_excerpt = breakpoint_position.excerpt_id;
10144        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10145        let buffer_snapshot = buffer.read(cx).snapshot();
10146
10147        let row = buffer_snapshot
10148            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10149            .row;
10150
10151        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10152        let anchor_end = snapshot
10153            .buffer_snapshot
10154            .anchor_after(Point::new(row, line_len));
10155
10156        let bp = self
10157            .breakpoint_store
10158            .as_ref()?
10159            .read_with(cx, |breakpoint_store, cx| {
10160                breakpoint_store
10161                    .breakpoints(
10162                        &buffer,
10163                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10164                        &buffer_snapshot,
10165                        cx,
10166                    )
10167                    .next()
10168                    .and_then(|(bp, _)| {
10169                        let breakpoint_row = buffer_snapshot
10170                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10171                            .row;
10172
10173                        if breakpoint_row == row {
10174                            snapshot
10175                                .buffer_snapshot
10176                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10177                                .map(|position| (position, bp.bp.clone()))
10178                        } else {
10179                            None
10180                        }
10181                    })
10182            });
10183        bp
10184    }
10185
10186    pub fn edit_log_breakpoint(
10187        &mut self,
10188        _: &EditLogBreakpoint,
10189        window: &mut Window,
10190        cx: &mut Context<Self>,
10191    ) {
10192        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10193            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10194                message: None,
10195                state: BreakpointState::Enabled,
10196                condition: None,
10197                hit_condition: None,
10198            });
10199
10200            self.add_edit_breakpoint_block(
10201                anchor,
10202                &breakpoint,
10203                BreakpointPromptEditAction::Log,
10204                window,
10205                cx,
10206            );
10207        }
10208    }
10209
10210    fn breakpoints_at_cursors(
10211        &self,
10212        window: &mut Window,
10213        cx: &mut Context<Self>,
10214    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10215        let snapshot = self.snapshot(window, cx);
10216        let cursors = self
10217            .selections
10218            .disjoint_anchors()
10219            .into_iter()
10220            .map(|selection| {
10221                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10222
10223                let breakpoint_position = self
10224                    .breakpoint_at_row(cursor_position.row, window, cx)
10225                    .map(|bp| bp.0)
10226                    .unwrap_or_else(|| {
10227                        snapshot
10228                            .display_snapshot
10229                            .buffer_snapshot
10230                            .anchor_after(Point::new(cursor_position.row, 0))
10231                    });
10232
10233                let breakpoint = self
10234                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10235                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10236
10237                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10238            })
10239            // 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.
10240            .collect::<HashMap<Anchor, _>>();
10241
10242        cursors.into_iter().collect()
10243    }
10244
10245    pub fn enable_breakpoint(
10246        &mut self,
10247        _: &crate::actions::EnableBreakpoint,
10248        window: &mut Window,
10249        cx: &mut Context<Self>,
10250    ) {
10251        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10252            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10253                continue;
10254            };
10255            self.edit_breakpoint_at_anchor(
10256                anchor,
10257                breakpoint,
10258                BreakpointEditAction::InvertState,
10259                cx,
10260            );
10261        }
10262    }
10263
10264    pub fn disable_breakpoint(
10265        &mut self,
10266        _: &crate::actions::DisableBreakpoint,
10267        window: &mut Window,
10268        cx: &mut Context<Self>,
10269    ) {
10270        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10271            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10272                continue;
10273            };
10274            self.edit_breakpoint_at_anchor(
10275                anchor,
10276                breakpoint,
10277                BreakpointEditAction::InvertState,
10278                cx,
10279            );
10280        }
10281    }
10282
10283    pub fn toggle_breakpoint(
10284        &mut self,
10285        _: &crate::actions::ToggleBreakpoint,
10286        window: &mut Window,
10287        cx: &mut Context<Self>,
10288    ) {
10289        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10290            if let Some(breakpoint) = breakpoint {
10291                self.edit_breakpoint_at_anchor(
10292                    anchor,
10293                    breakpoint,
10294                    BreakpointEditAction::Toggle,
10295                    cx,
10296                );
10297            } else {
10298                self.edit_breakpoint_at_anchor(
10299                    anchor,
10300                    Breakpoint::new_standard(),
10301                    BreakpointEditAction::Toggle,
10302                    cx,
10303                );
10304            }
10305        }
10306    }
10307
10308    pub fn edit_breakpoint_at_anchor(
10309        &mut self,
10310        breakpoint_position: Anchor,
10311        breakpoint: Breakpoint,
10312        edit_action: BreakpointEditAction,
10313        cx: &mut Context<Self>,
10314    ) {
10315        let Some(breakpoint_store) = &self.breakpoint_store else {
10316            return;
10317        };
10318
10319        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10320            if breakpoint_position == Anchor::min() {
10321                self.buffer()
10322                    .read(cx)
10323                    .excerpt_buffer_ids()
10324                    .into_iter()
10325                    .next()
10326            } else {
10327                None
10328            }
10329        }) else {
10330            return;
10331        };
10332
10333        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10334            return;
10335        };
10336
10337        breakpoint_store.update(cx, |breakpoint_store, cx| {
10338            breakpoint_store.toggle_breakpoint(
10339                buffer,
10340                BreakpointWithPosition {
10341                    position: breakpoint_position.text_anchor,
10342                    bp: breakpoint,
10343                },
10344                edit_action,
10345                cx,
10346            );
10347        });
10348
10349        cx.notify();
10350    }
10351
10352    #[cfg(any(test, feature = "test-support"))]
10353    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10354        self.breakpoint_store.clone()
10355    }
10356
10357    pub fn prepare_restore_change(
10358        &self,
10359        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10360        hunk: &MultiBufferDiffHunk,
10361        cx: &mut App,
10362    ) -> Option<()> {
10363        if hunk.is_created_file() {
10364            return None;
10365        }
10366        let buffer = self.buffer.read(cx);
10367        let diff = buffer.diff_for(hunk.buffer_id)?;
10368        let buffer = buffer.buffer(hunk.buffer_id)?;
10369        let buffer = buffer.read(cx);
10370        let original_text = diff
10371            .read(cx)
10372            .base_text()
10373            .as_rope()
10374            .slice(hunk.diff_base_byte_range.clone());
10375        let buffer_snapshot = buffer.snapshot();
10376        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10377        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10378            probe
10379                .0
10380                .start
10381                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10382                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10383        }) {
10384            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10385            Some(())
10386        } else {
10387            None
10388        }
10389    }
10390
10391    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10392        self.manipulate_lines(window, cx, |lines| lines.reverse())
10393    }
10394
10395    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10396        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10397    }
10398
10399    fn manipulate_lines<Fn>(
10400        &mut self,
10401        window: &mut Window,
10402        cx: &mut Context<Self>,
10403        mut callback: Fn,
10404    ) where
10405        Fn: FnMut(&mut Vec<&str>),
10406    {
10407        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10408
10409        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10410        let buffer = self.buffer.read(cx).snapshot(cx);
10411
10412        let mut edits = Vec::new();
10413
10414        let selections = self.selections.all::<Point>(cx);
10415        let mut selections = selections.iter().peekable();
10416        let mut contiguous_row_selections = Vec::new();
10417        let mut new_selections = Vec::new();
10418        let mut added_lines = 0;
10419        let mut removed_lines = 0;
10420
10421        while let Some(selection) = selections.next() {
10422            let (start_row, end_row) = consume_contiguous_rows(
10423                &mut contiguous_row_selections,
10424                selection,
10425                &display_map,
10426                &mut selections,
10427            );
10428
10429            let start_point = Point::new(start_row.0, 0);
10430            let end_point = Point::new(
10431                end_row.previous_row().0,
10432                buffer.line_len(end_row.previous_row()),
10433            );
10434            let text = buffer
10435                .text_for_range(start_point..end_point)
10436                .collect::<String>();
10437
10438            let mut lines = text.split('\n').collect_vec();
10439
10440            let lines_before = lines.len();
10441            callback(&mut lines);
10442            let lines_after = lines.len();
10443
10444            edits.push((start_point..end_point, lines.join("\n")));
10445
10446            // Selections must change based on added and removed line count
10447            let start_row =
10448                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10449            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10450            new_selections.push(Selection {
10451                id: selection.id,
10452                start: start_row,
10453                end: end_row,
10454                goal: SelectionGoal::None,
10455                reversed: selection.reversed,
10456            });
10457
10458            if lines_after > lines_before {
10459                added_lines += lines_after - lines_before;
10460            } else if lines_before > lines_after {
10461                removed_lines += lines_before - lines_after;
10462            }
10463        }
10464
10465        self.transact(window, cx, |this, window, cx| {
10466            let buffer = this.buffer.update(cx, |buffer, cx| {
10467                buffer.edit(edits, None, cx);
10468                buffer.snapshot(cx)
10469            });
10470
10471            // Recalculate offsets on newly edited buffer
10472            let new_selections = new_selections
10473                .iter()
10474                .map(|s| {
10475                    let start_point = Point::new(s.start.0, 0);
10476                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10477                    Selection {
10478                        id: s.id,
10479                        start: buffer.point_to_offset(start_point),
10480                        end: buffer.point_to_offset(end_point),
10481                        goal: s.goal,
10482                        reversed: s.reversed,
10483                    }
10484                })
10485                .collect();
10486
10487            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10488                s.select(new_selections);
10489            });
10490
10491            this.request_autoscroll(Autoscroll::fit(), cx);
10492        });
10493    }
10494
10495    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10496        self.manipulate_text(window, cx, |text| {
10497            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10498            if has_upper_case_characters {
10499                text.to_lowercase()
10500            } else {
10501                text.to_uppercase()
10502            }
10503        })
10504    }
10505
10506    pub fn convert_to_upper_case(
10507        &mut self,
10508        _: &ConvertToUpperCase,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.manipulate_text(window, cx, |text| text.to_uppercase())
10513    }
10514
10515    pub fn convert_to_lower_case(
10516        &mut self,
10517        _: &ConvertToLowerCase,
10518        window: &mut Window,
10519        cx: &mut Context<Self>,
10520    ) {
10521        self.manipulate_text(window, cx, |text| text.to_lowercase())
10522    }
10523
10524    pub fn convert_to_title_case(
10525        &mut self,
10526        _: &ConvertToTitleCase,
10527        window: &mut Window,
10528        cx: &mut Context<Self>,
10529    ) {
10530        self.manipulate_text(window, cx, |text| {
10531            text.split('\n')
10532                .map(|line| line.to_case(Case::Title))
10533                .join("\n")
10534        })
10535    }
10536
10537    pub fn convert_to_snake_case(
10538        &mut self,
10539        _: &ConvertToSnakeCase,
10540        window: &mut Window,
10541        cx: &mut Context<Self>,
10542    ) {
10543        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10544    }
10545
10546    pub fn convert_to_kebab_case(
10547        &mut self,
10548        _: &ConvertToKebabCase,
10549        window: &mut Window,
10550        cx: &mut Context<Self>,
10551    ) {
10552        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10553    }
10554
10555    pub fn convert_to_upper_camel_case(
10556        &mut self,
10557        _: &ConvertToUpperCamelCase,
10558        window: &mut Window,
10559        cx: &mut Context<Self>,
10560    ) {
10561        self.manipulate_text(window, cx, |text| {
10562            text.split('\n')
10563                .map(|line| line.to_case(Case::UpperCamel))
10564                .join("\n")
10565        })
10566    }
10567
10568    pub fn convert_to_lower_camel_case(
10569        &mut self,
10570        _: &ConvertToLowerCamelCase,
10571        window: &mut Window,
10572        cx: &mut Context<Self>,
10573    ) {
10574        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10575    }
10576
10577    pub fn convert_to_opposite_case(
10578        &mut self,
10579        _: &ConvertToOppositeCase,
10580        window: &mut Window,
10581        cx: &mut Context<Self>,
10582    ) {
10583        self.manipulate_text(window, cx, |text| {
10584            text.chars()
10585                .fold(String::with_capacity(text.len()), |mut t, c| {
10586                    if c.is_uppercase() {
10587                        t.extend(c.to_lowercase());
10588                    } else {
10589                        t.extend(c.to_uppercase());
10590                    }
10591                    t
10592                })
10593        })
10594    }
10595
10596    pub fn convert_to_rot13(
10597        &mut self,
10598        _: &ConvertToRot13,
10599        window: &mut Window,
10600        cx: &mut Context<Self>,
10601    ) {
10602        self.manipulate_text(window, cx, |text| {
10603            text.chars()
10604                .map(|c| match c {
10605                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10606                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10607                    _ => c,
10608                })
10609                .collect()
10610        })
10611    }
10612
10613    pub fn convert_to_rot47(
10614        &mut self,
10615        _: &ConvertToRot47,
10616        window: &mut Window,
10617        cx: &mut Context<Self>,
10618    ) {
10619        self.manipulate_text(window, cx, |text| {
10620            text.chars()
10621                .map(|c| {
10622                    let code_point = c as u32;
10623                    if code_point >= 33 && code_point <= 126 {
10624                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10625                    }
10626                    c
10627                })
10628                .collect()
10629        })
10630    }
10631
10632    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10633    where
10634        Fn: FnMut(&str) -> String,
10635    {
10636        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10637        let buffer = self.buffer.read(cx).snapshot(cx);
10638
10639        let mut new_selections = Vec::new();
10640        let mut edits = Vec::new();
10641        let mut selection_adjustment = 0i32;
10642
10643        for selection in self.selections.all::<usize>(cx) {
10644            let selection_is_empty = selection.is_empty();
10645
10646            let (start, end) = if selection_is_empty {
10647                let word_range = movement::surrounding_word(
10648                    &display_map,
10649                    selection.start.to_display_point(&display_map),
10650                );
10651                let start = word_range.start.to_offset(&display_map, Bias::Left);
10652                let end = word_range.end.to_offset(&display_map, Bias::Left);
10653                (start, end)
10654            } else {
10655                (selection.start, selection.end)
10656            };
10657
10658            let text = buffer.text_for_range(start..end).collect::<String>();
10659            let old_length = text.len() as i32;
10660            let text = callback(&text);
10661
10662            new_selections.push(Selection {
10663                start: (start as i32 - selection_adjustment) as usize,
10664                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10665                goal: SelectionGoal::None,
10666                ..selection
10667            });
10668
10669            selection_adjustment += old_length - text.len() as i32;
10670
10671            edits.push((start..end, text));
10672        }
10673
10674        self.transact(window, cx, |this, window, cx| {
10675            this.buffer.update(cx, |buffer, cx| {
10676                buffer.edit(edits, None, cx);
10677            });
10678
10679            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10680                s.select(new_selections);
10681            });
10682
10683            this.request_autoscroll(Autoscroll::fit(), cx);
10684        });
10685    }
10686
10687    pub fn move_selection_on_drop(
10688        &mut self,
10689        selection: &Selection<Anchor>,
10690        target: DisplayPoint,
10691        is_cut: bool,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10696        let buffer = &display_map.buffer_snapshot;
10697        let mut edits = Vec::new();
10698        let insert_point = display_map
10699            .clip_point(target, Bias::Left)
10700            .to_point(&display_map);
10701        let text = buffer
10702            .text_for_range(selection.start..selection.end)
10703            .collect::<String>();
10704        if is_cut {
10705            edits.push(((selection.start..selection.end), String::new()));
10706        }
10707        let insert_anchor = buffer.anchor_before(insert_point);
10708        edits.push(((insert_anchor..insert_anchor), text));
10709        let last_edit_start = insert_anchor.bias_left(buffer);
10710        let last_edit_end = insert_anchor.bias_right(buffer);
10711        self.transact(window, cx, |this, window, cx| {
10712            this.buffer.update(cx, |buffer, cx| {
10713                buffer.edit(edits, None, cx);
10714            });
10715            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10716                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10717            });
10718        });
10719    }
10720
10721    pub fn clear_selection_drag_state(&mut self) {
10722        self.selection_drag_state = SelectionDragState::None;
10723    }
10724
10725    pub fn duplicate(
10726        &mut self,
10727        upwards: bool,
10728        whole_lines: bool,
10729        window: &mut Window,
10730        cx: &mut Context<Self>,
10731    ) {
10732        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10733
10734        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10735        let buffer = &display_map.buffer_snapshot;
10736        let selections = self.selections.all::<Point>(cx);
10737
10738        let mut edits = Vec::new();
10739        let mut selections_iter = selections.iter().peekable();
10740        while let Some(selection) = selections_iter.next() {
10741            let mut rows = selection.spanned_rows(false, &display_map);
10742            // duplicate line-wise
10743            if whole_lines || selection.start == selection.end {
10744                // Avoid duplicating the same lines twice.
10745                while let Some(next_selection) = selections_iter.peek() {
10746                    let next_rows = next_selection.spanned_rows(false, &display_map);
10747                    if next_rows.start < rows.end {
10748                        rows.end = next_rows.end;
10749                        selections_iter.next().unwrap();
10750                    } else {
10751                        break;
10752                    }
10753                }
10754
10755                // Copy the text from the selected row region and splice it either at the start
10756                // or end of the region.
10757                let start = Point::new(rows.start.0, 0);
10758                let end = Point::new(
10759                    rows.end.previous_row().0,
10760                    buffer.line_len(rows.end.previous_row()),
10761                );
10762                let text = buffer
10763                    .text_for_range(start..end)
10764                    .chain(Some("\n"))
10765                    .collect::<String>();
10766                let insert_location = if upwards {
10767                    Point::new(rows.end.0, 0)
10768                } else {
10769                    start
10770                };
10771                edits.push((insert_location..insert_location, text));
10772            } else {
10773                // duplicate character-wise
10774                let start = selection.start;
10775                let end = selection.end;
10776                let text = buffer.text_for_range(start..end).collect::<String>();
10777                edits.push((selection.end..selection.end, text));
10778            }
10779        }
10780
10781        self.transact(window, cx, |this, _, cx| {
10782            this.buffer.update(cx, |buffer, cx| {
10783                buffer.edit(edits, None, cx);
10784            });
10785
10786            this.request_autoscroll(Autoscroll::fit(), cx);
10787        });
10788    }
10789
10790    pub fn duplicate_line_up(
10791        &mut self,
10792        _: &DuplicateLineUp,
10793        window: &mut Window,
10794        cx: &mut Context<Self>,
10795    ) {
10796        self.duplicate(true, true, window, cx);
10797    }
10798
10799    pub fn duplicate_line_down(
10800        &mut self,
10801        _: &DuplicateLineDown,
10802        window: &mut Window,
10803        cx: &mut Context<Self>,
10804    ) {
10805        self.duplicate(false, true, window, cx);
10806    }
10807
10808    pub fn duplicate_selection(
10809        &mut self,
10810        _: &DuplicateSelection,
10811        window: &mut Window,
10812        cx: &mut Context<Self>,
10813    ) {
10814        self.duplicate(false, false, window, cx);
10815    }
10816
10817    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10818        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10819
10820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10821        let buffer = self.buffer.read(cx).snapshot(cx);
10822
10823        let mut edits = Vec::new();
10824        let mut unfold_ranges = Vec::new();
10825        let mut refold_creases = Vec::new();
10826
10827        let selections = self.selections.all::<Point>(cx);
10828        let mut selections = selections.iter().peekable();
10829        let mut contiguous_row_selections = Vec::new();
10830        let mut new_selections = Vec::new();
10831
10832        while let Some(selection) = selections.next() {
10833            // Find all the selections that span a contiguous row range
10834            let (start_row, end_row) = consume_contiguous_rows(
10835                &mut contiguous_row_selections,
10836                selection,
10837                &display_map,
10838                &mut selections,
10839            );
10840
10841            // Move the text spanned by the row range to be before the line preceding the row range
10842            if start_row.0 > 0 {
10843                let range_to_move = Point::new(
10844                    start_row.previous_row().0,
10845                    buffer.line_len(start_row.previous_row()),
10846                )
10847                    ..Point::new(
10848                        end_row.previous_row().0,
10849                        buffer.line_len(end_row.previous_row()),
10850                    );
10851                let insertion_point = display_map
10852                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10853                    .0;
10854
10855                // Don't move lines across excerpts
10856                if buffer
10857                    .excerpt_containing(insertion_point..range_to_move.end)
10858                    .is_some()
10859                {
10860                    let text = buffer
10861                        .text_for_range(range_to_move.clone())
10862                        .flat_map(|s| s.chars())
10863                        .skip(1)
10864                        .chain(['\n'])
10865                        .collect::<String>();
10866
10867                    edits.push((
10868                        buffer.anchor_after(range_to_move.start)
10869                            ..buffer.anchor_before(range_to_move.end),
10870                        String::new(),
10871                    ));
10872                    let insertion_anchor = buffer.anchor_after(insertion_point);
10873                    edits.push((insertion_anchor..insertion_anchor, text));
10874
10875                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10876
10877                    // Move selections up
10878                    new_selections.extend(contiguous_row_selections.drain(..).map(
10879                        |mut selection| {
10880                            selection.start.row -= row_delta;
10881                            selection.end.row -= row_delta;
10882                            selection
10883                        },
10884                    ));
10885
10886                    // Move folds up
10887                    unfold_ranges.push(range_to_move.clone());
10888                    for fold in display_map.folds_in_range(
10889                        buffer.anchor_before(range_to_move.start)
10890                            ..buffer.anchor_after(range_to_move.end),
10891                    ) {
10892                        let mut start = fold.range.start.to_point(&buffer);
10893                        let mut end = fold.range.end.to_point(&buffer);
10894                        start.row -= row_delta;
10895                        end.row -= row_delta;
10896                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10897                    }
10898                }
10899            }
10900
10901            // If we didn't move line(s), preserve the existing selections
10902            new_selections.append(&mut contiguous_row_selections);
10903        }
10904
10905        self.transact(window, cx, |this, window, cx| {
10906            this.unfold_ranges(&unfold_ranges, true, true, cx);
10907            this.buffer.update(cx, |buffer, cx| {
10908                for (range, text) in edits {
10909                    buffer.edit([(range, text)], None, cx);
10910                }
10911            });
10912            this.fold_creases(refold_creases, true, window, cx);
10913            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10914                s.select(new_selections);
10915            })
10916        });
10917    }
10918
10919    pub fn move_line_down(
10920        &mut self,
10921        _: &MoveLineDown,
10922        window: &mut Window,
10923        cx: &mut Context<Self>,
10924    ) {
10925        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10926
10927        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10928        let buffer = self.buffer.read(cx).snapshot(cx);
10929
10930        let mut edits = Vec::new();
10931        let mut unfold_ranges = Vec::new();
10932        let mut refold_creases = Vec::new();
10933
10934        let selections = self.selections.all::<Point>(cx);
10935        let mut selections = selections.iter().peekable();
10936        let mut contiguous_row_selections = Vec::new();
10937        let mut new_selections = Vec::new();
10938
10939        while let Some(selection) = selections.next() {
10940            // Find all the selections that span a contiguous row range
10941            let (start_row, end_row) = consume_contiguous_rows(
10942                &mut contiguous_row_selections,
10943                selection,
10944                &display_map,
10945                &mut selections,
10946            );
10947
10948            // Move the text spanned by the row range to be after the last line of the row range
10949            if end_row.0 <= buffer.max_point().row {
10950                let range_to_move =
10951                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10952                let insertion_point = display_map
10953                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10954                    .0;
10955
10956                // Don't move lines across excerpt boundaries
10957                if buffer
10958                    .excerpt_containing(range_to_move.start..insertion_point)
10959                    .is_some()
10960                {
10961                    let mut text = String::from("\n");
10962                    text.extend(buffer.text_for_range(range_to_move.clone()));
10963                    text.pop(); // Drop trailing newline
10964                    edits.push((
10965                        buffer.anchor_after(range_to_move.start)
10966                            ..buffer.anchor_before(range_to_move.end),
10967                        String::new(),
10968                    ));
10969                    let insertion_anchor = buffer.anchor_after(insertion_point);
10970                    edits.push((insertion_anchor..insertion_anchor, text));
10971
10972                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10973
10974                    // Move selections down
10975                    new_selections.extend(contiguous_row_selections.drain(..).map(
10976                        |mut selection| {
10977                            selection.start.row += row_delta;
10978                            selection.end.row += row_delta;
10979                            selection
10980                        },
10981                    ));
10982
10983                    // Move folds down
10984                    unfold_ranges.push(range_to_move.clone());
10985                    for fold in display_map.folds_in_range(
10986                        buffer.anchor_before(range_to_move.start)
10987                            ..buffer.anchor_after(range_to_move.end),
10988                    ) {
10989                        let mut start = fold.range.start.to_point(&buffer);
10990                        let mut end = fold.range.end.to_point(&buffer);
10991                        start.row += row_delta;
10992                        end.row += row_delta;
10993                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10994                    }
10995                }
10996            }
10997
10998            // If we didn't move line(s), preserve the existing selections
10999            new_selections.append(&mut contiguous_row_selections);
11000        }
11001
11002        self.transact(window, cx, |this, window, cx| {
11003            this.unfold_ranges(&unfold_ranges, true, true, cx);
11004            this.buffer.update(cx, |buffer, cx| {
11005                for (range, text) in edits {
11006                    buffer.edit([(range, text)], None, cx);
11007                }
11008            });
11009            this.fold_creases(refold_creases, true, window, cx);
11010            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11011                s.select(new_selections)
11012            });
11013        });
11014    }
11015
11016    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11017        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11018        let text_layout_details = &self.text_layout_details(window);
11019        self.transact(window, cx, |this, window, cx| {
11020            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11021                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11022                s.move_with(|display_map, selection| {
11023                    if !selection.is_empty() {
11024                        return;
11025                    }
11026
11027                    let mut head = selection.head();
11028                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11029                    if head.column() == display_map.line_len(head.row()) {
11030                        transpose_offset = display_map
11031                            .buffer_snapshot
11032                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11033                    }
11034
11035                    if transpose_offset == 0 {
11036                        return;
11037                    }
11038
11039                    *head.column_mut() += 1;
11040                    head = display_map.clip_point(head, Bias::Right);
11041                    let goal = SelectionGoal::HorizontalPosition(
11042                        display_map
11043                            .x_for_display_point(head, text_layout_details)
11044                            .into(),
11045                    );
11046                    selection.collapse_to(head, goal);
11047
11048                    let transpose_start = display_map
11049                        .buffer_snapshot
11050                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11051                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11052                        let transpose_end = display_map
11053                            .buffer_snapshot
11054                            .clip_offset(transpose_offset + 1, Bias::Right);
11055                        if let Some(ch) =
11056                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11057                        {
11058                            edits.push((transpose_start..transpose_offset, String::new()));
11059                            edits.push((transpose_end..transpose_end, ch.to_string()));
11060                        }
11061                    }
11062                });
11063                edits
11064            });
11065            this.buffer
11066                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11067            let selections = this.selections.all::<usize>(cx);
11068            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11069                s.select(selections);
11070            });
11071        });
11072    }
11073
11074    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11075        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11076        self.rewrap_impl(RewrapOptions::default(), cx)
11077    }
11078
11079    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11080        let buffer = self.buffer.read(cx).snapshot(cx);
11081        let selections = self.selections.all::<Point>(cx);
11082
11083        // Shrink and split selections to respect paragraph boundaries.
11084        let ranges = selections.into_iter().flat_map(|selection| {
11085            let language_settings = buffer.language_settings_at(selection.head(), cx);
11086            let language_scope = buffer.language_scope_at(selection.head());
11087
11088            let Some(start_row) = (selection.start.row..=selection.end.row)
11089                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11090            else {
11091                return vec![];
11092            };
11093            let Some(end_row) = (selection.start.row..=selection.end.row)
11094                .rev()
11095                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11096            else {
11097                return vec![];
11098            };
11099
11100            let mut row = start_row;
11101            let mut ranges = Vec::new();
11102            while let Some(blank_row) =
11103                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11104            {
11105                let next_paragraph_start = (blank_row + 1..=end_row)
11106                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11107                    .unwrap();
11108                ranges.push((
11109                    language_settings.clone(),
11110                    language_scope.clone(),
11111                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11112                ));
11113                row = next_paragraph_start;
11114            }
11115            ranges.push((
11116                language_settings.clone(),
11117                language_scope.clone(),
11118                Point::new(row, 0)..Point::new(end_row, 0),
11119            ));
11120
11121            ranges
11122        });
11123
11124        let mut edits = Vec::new();
11125        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11126
11127        for (language_settings, language_scope, range) in ranges {
11128            let mut start_row = range.start.row;
11129            let mut end_row = range.end.row;
11130
11131            // Skip selections that overlap with a range that has already been rewrapped.
11132            let selection_range = start_row..end_row;
11133            if rewrapped_row_ranges
11134                .iter()
11135                .any(|range| range.overlaps(&selection_range))
11136            {
11137                continue;
11138            }
11139
11140            let tab_size = language_settings.tab_size;
11141
11142            // Since not all lines in the selection may be at the same indent
11143            // level, choose the indent size that is the most common between all
11144            // of the lines.
11145            //
11146            // If there is a tie, we use the deepest indent.
11147            let (indent_size, indent_end) = {
11148                let mut indent_size_occurrences = HashMap::default();
11149                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11150
11151                for row in start_row..=end_row {
11152                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11153                    rows_by_indent_size.entry(indent).or_default().push(row);
11154                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11155                }
11156
11157                let indent_size = indent_size_occurrences
11158                    .into_iter()
11159                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11160                    .map(|(indent, _)| indent)
11161                    .unwrap_or_default();
11162                let row = rows_by_indent_size[&indent_size][0];
11163                let indent_end = Point::new(row, indent_size.len);
11164
11165                (indent_size, indent_end)
11166            };
11167
11168            let mut line_prefix = indent_size.chars().collect::<String>();
11169
11170            let mut inside_comment = false;
11171            if let Some(comment_prefix) = language_scope.and_then(|language| {
11172                language
11173                    .line_comment_prefixes()
11174                    .iter()
11175                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11176                    .cloned()
11177            }) {
11178                line_prefix.push_str(&comment_prefix);
11179                inside_comment = true;
11180            }
11181
11182            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11183                RewrapBehavior::InComments => inside_comment,
11184                RewrapBehavior::InSelections => !range.is_empty(),
11185                RewrapBehavior::Anywhere => true,
11186            };
11187
11188            let should_rewrap = options.override_language_settings
11189                || allow_rewrap_based_on_language
11190                || self.hard_wrap.is_some();
11191            if !should_rewrap {
11192                continue;
11193            }
11194
11195            if range.is_empty() {
11196                'expand_upwards: while start_row > 0 {
11197                    let prev_row = start_row - 1;
11198                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11199                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11200                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11201                    {
11202                        start_row = prev_row;
11203                    } else {
11204                        break 'expand_upwards;
11205                    }
11206                }
11207
11208                'expand_downwards: while end_row < buffer.max_point().row {
11209                    let next_row = end_row + 1;
11210                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11211                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11212                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11213                    {
11214                        end_row = next_row;
11215                    } else {
11216                        break 'expand_downwards;
11217                    }
11218                }
11219            }
11220
11221            let start = Point::new(start_row, 0);
11222            let start_offset = start.to_offset(&buffer);
11223            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11224            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11225            let Some(lines_without_prefixes) = selection_text
11226                .lines()
11227                .map(|line| {
11228                    line.strip_prefix(&line_prefix)
11229                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11230                        .with_context(|| {
11231                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11232                        })
11233                })
11234                .collect::<Result<Vec<_>, _>>()
11235                .log_err()
11236            else {
11237                continue;
11238            };
11239
11240            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11241                buffer
11242                    .language_settings_at(Point::new(start_row, 0), cx)
11243                    .preferred_line_length as usize
11244            });
11245            let wrapped_text = wrap_with_prefix(
11246                line_prefix,
11247                lines_without_prefixes.join("\n"),
11248                wrap_column,
11249                tab_size,
11250                options.preserve_existing_whitespace,
11251            );
11252
11253            // TODO: should always use char-based diff while still supporting cursor behavior that
11254            // matches vim.
11255            let mut diff_options = DiffOptions::default();
11256            if options.override_language_settings {
11257                diff_options.max_word_diff_len = 0;
11258                diff_options.max_word_diff_line_count = 0;
11259            } else {
11260                diff_options.max_word_diff_len = usize::MAX;
11261                diff_options.max_word_diff_line_count = usize::MAX;
11262            }
11263
11264            for (old_range, new_text) in
11265                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11266            {
11267                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11268                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11269                edits.push((edit_start..edit_end, new_text));
11270            }
11271
11272            rewrapped_row_ranges.push(start_row..=end_row);
11273        }
11274
11275        self.buffer
11276            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11277    }
11278
11279    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11280        let mut text = String::new();
11281        let buffer = self.buffer.read(cx).snapshot(cx);
11282        let mut selections = self.selections.all::<Point>(cx);
11283        let mut clipboard_selections = Vec::with_capacity(selections.len());
11284        {
11285            let max_point = buffer.max_point();
11286            let mut is_first = true;
11287            for selection in &mut selections {
11288                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11289                if is_entire_line {
11290                    selection.start = Point::new(selection.start.row, 0);
11291                    if !selection.is_empty() && selection.end.column == 0 {
11292                        selection.end = cmp::min(max_point, selection.end);
11293                    } else {
11294                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11295                    }
11296                    selection.goal = SelectionGoal::None;
11297                }
11298                if is_first {
11299                    is_first = false;
11300                } else {
11301                    text += "\n";
11302                }
11303                let mut len = 0;
11304                for chunk in buffer.text_for_range(selection.start..selection.end) {
11305                    text.push_str(chunk);
11306                    len += chunk.len();
11307                }
11308                clipboard_selections.push(ClipboardSelection {
11309                    len,
11310                    is_entire_line,
11311                    first_line_indent: buffer
11312                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11313                        .len,
11314                });
11315            }
11316        }
11317
11318        self.transact(window, cx, |this, window, cx| {
11319            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11320                s.select(selections);
11321            });
11322            this.insert("", window, cx);
11323        });
11324        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11325    }
11326
11327    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11328        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11329        let item = self.cut_common(window, cx);
11330        cx.write_to_clipboard(item);
11331    }
11332
11333    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11334        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11335        self.change_selections(None, window, cx, |s| {
11336            s.move_with(|snapshot, sel| {
11337                if sel.is_empty() {
11338                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11339                }
11340            });
11341        });
11342        let item = self.cut_common(window, cx);
11343        cx.set_global(KillRing(item))
11344    }
11345
11346    pub fn kill_ring_yank(
11347        &mut self,
11348        _: &KillRingYank,
11349        window: &mut Window,
11350        cx: &mut Context<Self>,
11351    ) {
11352        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11353        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11354            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11355                (kill_ring.text().to_string(), kill_ring.metadata_json())
11356            } else {
11357                return;
11358            }
11359        } else {
11360            return;
11361        };
11362        self.do_paste(&text, metadata, false, window, cx);
11363    }
11364
11365    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11366        self.do_copy(true, cx);
11367    }
11368
11369    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11370        self.do_copy(false, cx);
11371    }
11372
11373    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11374        let selections = self.selections.all::<Point>(cx);
11375        let buffer = self.buffer.read(cx).read(cx);
11376        let mut text = String::new();
11377
11378        let mut clipboard_selections = Vec::with_capacity(selections.len());
11379        {
11380            let max_point = buffer.max_point();
11381            let mut is_first = true;
11382            for selection in &selections {
11383                let mut start = selection.start;
11384                let mut end = selection.end;
11385                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11386                if is_entire_line {
11387                    start = Point::new(start.row, 0);
11388                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11389                }
11390
11391                let mut trimmed_selections = Vec::new();
11392                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11393                    let row = MultiBufferRow(start.row);
11394                    let first_indent = buffer.indent_size_for_line(row);
11395                    if first_indent.len == 0 || start.column > first_indent.len {
11396                        trimmed_selections.push(start..end);
11397                    } else {
11398                        trimmed_selections.push(
11399                            Point::new(row.0, first_indent.len)
11400                                ..Point::new(row.0, buffer.line_len(row)),
11401                        );
11402                        for row in start.row + 1..=end.row {
11403                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11404                            if row == end.row {
11405                                line_len = end.column;
11406                            }
11407                            if line_len == 0 {
11408                                trimmed_selections
11409                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11410                                continue;
11411                            }
11412                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11413                            if row_indent_size.len >= first_indent.len {
11414                                trimmed_selections.push(
11415                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11416                                );
11417                            } else {
11418                                trimmed_selections.clear();
11419                                trimmed_selections.push(start..end);
11420                                break;
11421                            }
11422                        }
11423                    }
11424                } else {
11425                    trimmed_selections.push(start..end);
11426                }
11427
11428                for trimmed_range in trimmed_selections {
11429                    if is_first {
11430                        is_first = false;
11431                    } else {
11432                        text += "\n";
11433                    }
11434                    let mut len = 0;
11435                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11436                        text.push_str(chunk);
11437                        len += chunk.len();
11438                    }
11439                    clipboard_selections.push(ClipboardSelection {
11440                        len,
11441                        is_entire_line,
11442                        first_line_indent: buffer
11443                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11444                            .len,
11445                    });
11446                }
11447            }
11448        }
11449
11450        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11451            text,
11452            clipboard_selections,
11453        ));
11454    }
11455
11456    pub fn do_paste(
11457        &mut self,
11458        text: &String,
11459        clipboard_selections: Option<Vec<ClipboardSelection>>,
11460        handle_entire_lines: bool,
11461        window: &mut Window,
11462        cx: &mut Context<Self>,
11463    ) {
11464        if self.read_only(cx) {
11465            return;
11466        }
11467
11468        let clipboard_text = Cow::Borrowed(text);
11469
11470        self.transact(window, cx, |this, window, cx| {
11471            if let Some(mut clipboard_selections) = clipboard_selections {
11472                let old_selections = this.selections.all::<usize>(cx);
11473                let all_selections_were_entire_line =
11474                    clipboard_selections.iter().all(|s| s.is_entire_line);
11475                let first_selection_indent_column =
11476                    clipboard_selections.first().map(|s| s.first_line_indent);
11477                if clipboard_selections.len() != old_selections.len() {
11478                    clipboard_selections.drain(..);
11479                }
11480                let cursor_offset = this.selections.last::<usize>(cx).head();
11481                let mut auto_indent_on_paste = true;
11482
11483                this.buffer.update(cx, |buffer, cx| {
11484                    let snapshot = buffer.read(cx);
11485                    auto_indent_on_paste = snapshot
11486                        .language_settings_at(cursor_offset, cx)
11487                        .auto_indent_on_paste;
11488
11489                    let mut start_offset = 0;
11490                    let mut edits = Vec::new();
11491                    let mut original_indent_columns = Vec::new();
11492                    for (ix, selection) in old_selections.iter().enumerate() {
11493                        let to_insert;
11494                        let entire_line;
11495                        let original_indent_column;
11496                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11497                            let end_offset = start_offset + clipboard_selection.len;
11498                            to_insert = &clipboard_text[start_offset..end_offset];
11499                            entire_line = clipboard_selection.is_entire_line;
11500                            start_offset = end_offset + 1;
11501                            original_indent_column = Some(clipboard_selection.first_line_indent);
11502                        } else {
11503                            to_insert = clipboard_text.as_str();
11504                            entire_line = all_selections_were_entire_line;
11505                            original_indent_column = first_selection_indent_column
11506                        }
11507
11508                        // If the corresponding selection was empty when this slice of the
11509                        // clipboard text was written, then the entire line containing the
11510                        // selection was copied. If this selection is also currently empty,
11511                        // then paste the line before the current line of the buffer.
11512                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11513                            let column = selection.start.to_point(&snapshot).column as usize;
11514                            let line_start = selection.start - column;
11515                            line_start..line_start
11516                        } else {
11517                            selection.range()
11518                        };
11519
11520                        edits.push((range, to_insert));
11521                        original_indent_columns.push(original_indent_column);
11522                    }
11523                    drop(snapshot);
11524
11525                    buffer.edit(
11526                        edits,
11527                        if auto_indent_on_paste {
11528                            Some(AutoindentMode::Block {
11529                                original_indent_columns,
11530                            })
11531                        } else {
11532                            None
11533                        },
11534                        cx,
11535                    );
11536                });
11537
11538                let selections = this.selections.all::<usize>(cx);
11539                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11540                    s.select(selections)
11541                });
11542            } else {
11543                this.insert(&clipboard_text, window, cx);
11544            }
11545        });
11546    }
11547
11548    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11549        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11550        if let Some(item) = cx.read_from_clipboard() {
11551            let entries = item.entries();
11552
11553            match entries.first() {
11554                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11555                // of all the pasted entries.
11556                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11557                    .do_paste(
11558                        clipboard_string.text(),
11559                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11560                        true,
11561                        window,
11562                        cx,
11563                    ),
11564                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11565            }
11566        }
11567    }
11568
11569    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11570        if self.read_only(cx) {
11571            return;
11572        }
11573
11574        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11575
11576        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11577            if let Some((selections, _)) =
11578                self.selection_history.transaction(transaction_id).cloned()
11579            {
11580                self.change_selections(None, window, cx, |s| {
11581                    s.select_anchors(selections.to_vec());
11582                });
11583            } else {
11584                log::error!(
11585                    "No entry in selection_history found for undo. \
11586                     This may correspond to a bug where undo does not update the selection. \
11587                     If this is occurring, please add details to \
11588                     https://github.com/zed-industries/zed/issues/22692"
11589                );
11590            }
11591            self.request_autoscroll(Autoscroll::fit(), cx);
11592            self.unmark_text(window, cx);
11593            self.refresh_inline_completion(true, false, window, cx);
11594            cx.emit(EditorEvent::Edited { transaction_id });
11595            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11596        }
11597    }
11598
11599    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11600        if self.read_only(cx) {
11601            return;
11602        }
11603
11604        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11605
11606        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11607            if let Some((_, Some(selections))) =
11608                self.selection_history.transaction(transaction_id).cloned()
11609            {
11610                self.change_selections(None, window, cx, |s| {
11611                    s.select_anchors(selections.to_vec());
11612                });
11613            } else {
11614                log::error!(
11615                    "No entry in selection_history found for redo. \
11616                     This may correspond to a bug where undo does not update the selection. \
11617                     If this is occurring, please add details to \
11618                     https://github.com/zed-industries/zed/issues/22692"
11619                );
11620            }
11621            self.request_autoscroll(Autoscroll::fit(), cx);
11622            self.unmark_text(window, cx);
11623            self.refresh_inline_completion(true, false, window, cx);
11624            cx.emit(EditorEvent::Edited { transaction_id });
11625        }
11626    }
11627
11628    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11629        self.buffer
11630            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11631    }
11632
11633    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11634        self.buffer
11635            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11636    }
11637
11638    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11639        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11640        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11641            s.move_with(|map, selection| {
11642                let cursor = if selection.is_empty() {
11643                    movement::left(map, selection.start)
11644                } else {
11645                    selection.start
11646                };
11647                selection.collapse_to(cursor, SelectionGoal::None);
11648            });
11649        })
11650    }
11651
11652    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11653        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11654        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11655            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11656        })
11657    }
11658
11659    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11660        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11661        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11662            s.move_with(|map, selection| {
11663                let cursor = if selection.is_empty() {
11664                    movement::right(map, selection.end)
11665                } else {
11666                    selection.end
11667                };
11668                selection.collapse_to(cursor, SelectionGoal::None)
11669            });
11670        })
11671    }
11672
11673    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11674        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11675        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11676            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11677        })
11678    }
11679
11680    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11681        if self.take_rename(true, window, cx).is_some() {
11682            return;
11683        }
11684
11685        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11686            cx.propagate();
11687            return;
11688        }
11689
11690        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11691
11692        let text_layout_details = &self.text_layout_details(window);
11693        let selection_count = self.selections.count();
11694        let first_selection = self.selections.first_anchor();
11695
11696        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11697            s.move_with(|map, selection| {
11698                if !selection.is_empty() {
11699                    selection.goal = SelectionGoal::None;
11700                }
11701                let (cursor, goal) = movement::up(
11702                    map,
11703                    selection.start,
11704                    selection.goal,
11705                    false,
11706                    text_layout_details,
11707                );
11708                selection.collapse_to(cursor, goal);
11709            });
11710        });
11711
11712        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11713        {
11714            cx.propagate();
11715        }
11716    }
11717
11718    pub fn move_up_by_lines(
11719        &mut self,
11720        action: &MoveUpByLines,
11721        window: &mut Window,
11722        cx: &mut Context<Self>,
11723    ) {
11724        if self.take_rename(true, window, cx).is_some() {
11725            return;
11726        }
11727
11728        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11729            cx.propagate();
11730            return;
11731        }
11732
11733        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11734
11735        let text_layout_details = &self.text_layout_details(window);
11736
11737        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11738            s.move_with(|map, selection| {
11739                if !selection.is_empty() {
11740                    selection.goal = SelectionGoal::None;
11741                }
11742                let (cursor, goal) = movement::up_by_rows(
11743                    map,
11744                    selection.start,
11745                    action.lines,
11746                    selection.goal,
11747                    false,
11748                    text_layout_details,
11749                );
11750                selection.collapse_to(cursor, goal);
11751            });
11752        })
11753    }
11754
11755    pub fn move_down_by_lines(
11756        &mut self,
11757        action: &MoveDownByLines,
11758        window: &mut Window,
11759        cx: &mut Context<Self>,
11760    ) {
11761        if self.take_rename(true, window, cx).is_some() {
11762            return;
11763        }
11764
11765        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11766            cx.propagate();
11767            return;
11768        }
11769
11770        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11771
11772        let text_layout_details = &self.text_layout_details(window);
11773
11774        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11775            s.move_with(|map, selection| {
11776                if !selection.is_empty() {
11777                    selection.goal = SelectionGoal::None;
11778                }
11779                let (cursor, goal) = movement::down_by_rows(
11780                    map,
11781                    selection.start,
11782                    action.lines,
11783                    selection.goal,
11784                    false,
11785                    text_layout_details,
11786                );
11787                selection.collapse_to(cursor, goal);
11788            });
11789        })
11790    }
11791
11792    pub fn select_down_by_lines(
11793        &mut self,
11794        action: &SelectDownByLines,
11795        window: &mut Window,
11796        cx: &mut Context<Self>,
11797    ) {
11798        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11799        let text_layout_details = &self.text_layout_details(window);
11800        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11801            s.move_heads_with(|map, head, goal| {
11802                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11803            })
11804        })
11805    }
11806
11807    pub fn select_up_by_lines(
11808        &mut self,
11809        action: &SelectUpByLines,
11810        window: &mut Window,
11811        cx: &mut Context<Self>,
11812    ) {
11813        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11814        let text_layout_details = &self.text_layout_details(window);
11815        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11816            s.move_heads_with(|map, head, goal| {
11817                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11818            })
11819        })
11820    }
11821
11822    pub fn select_page_up(
11823        &mut self,
11824        _: &SelectPageUp,
11825        window: &mut Window,
11826        cx: &mut Context<Self>,
11827    ) {
11828        let Some(row_count) = self.visible_row_count() else {
11829            return;
11830        };
11831
11832        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11833
11834        let text_layout_details = &self.text_layout_details(window);
11835
11836        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11837            s.move_heads_with(|map, head, goal| {
11838                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11839            })
11840        })
11841    }
11842
11843    pub fn move_page_up(
11844        &mut self,
11845        action: &MovePageUp,
11846        window: &mut Window,
11847        cx: &mut Context<Self>,
11848    ) {
11849        if self.take_rename(true, window, cx).is_some() {
11850            return;
11851        }
11852
11853        if self
11854            .context_menu
11855            .borrow_mut()
11856            .as_mut()
11857            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11858            .unwrap_or(false)
11859        {
11860            return;
11861        }
11862
11863        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11864            cx.propagate();
11865            return;
11866        }
11867
11868        let Some(row_count) = self.visible_row_count() else {
11869            return;
11870        };
11871
11872        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11873
11874        let autoscroll = if action.center_cursor {
11875            Autoscroll::center()
11876        } else {
11877            Autoscroll::fit()
11878        };
11879
11880        let text_layout_details = &self.text_layout_details(window);
11881
11882        self.change_selections(Some(autoscroll), window, cx, |s| {
11883            s.move_with(|map, selection| {
11884                if !selection.is_empty() {
11885                    selection.goal = SelectionGoal::None;
11886                }
11887                let (cursor, goal) = movement::up_by_rows(
11888                    map,
11889                    selection.end,
11890                    row_count,
11891                    selection.goal,
11892                    false,
11893                    text_layout_details,
11894                );
11895                selection.collapse_to(cursor, goal);
11896            });
11897        });
11898    }
11899
11900    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11901        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11902        let text_layout_details = &self.text_layout_details(window);
11903        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11904            s.move_heads_with(|map, head, goal| {
11905                movement::up(map, head, goal, false, text_layout_details)
11906            })
11907        })
11908    }
11909
11910    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11911        self.take_rename(true, window, cx);
11912
11913        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11914            cx.propagate();
11915            return;
11916        }
11917
11918        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11919
11920        let text_layout_details = &self.text_layout_details(window);
11921        let selection_count = self.selections.count();
11922        let first_selection = self.selections.first_anchor();
11923
11924        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11925            s.move_with(|map, selection| {
11926                if !selection.is_empty() {
11927                    selection.goal = SelectionGoal::None;
11928                }
11929                let (cursor, goal) = movement::down(
11930                    map,
11931                    selection.end,
11932                    selection.goal,
11933                    false,
11934                    text_layout_details,
11935                );
11936                selection.collapse_to(cursor, goal);
11937            });
11938        });
11939
11940        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11941        {
11942            cx.propagate();
11943        }
11944    }
11945
11946    pub fn select_page_down(
11947        &mut self,
11948        _: &SelectPageDown,
11949        window: &mut Window,
11950        cx: &mut Context<Self>,
11951    ) {
11952        let Some(row_count) = self.visible_row_count() else {
11953            return;
11954        };
11955
11956        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11957
11958        let text_layout_details = &self.text_layout_details(window);
11959
11960        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11961            s.move_heads_with(|map, head, goal| {
11962                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11963            })
11964        })
11965    }
11966
11967    pub fn move_page_down(
11968        &mut self,
11969        action: &MovePageDown,
11970        window: &mut Window,
11971        cx: &mut Context<Self>,
11972    ) {
11973        if self.take_rename(true, window, cx).is_some() {
11974            return;
11975        }
11976
11977        if self
11978            .context_menu
11979            .borrow_mut()
11980            .as_mut()
11981            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11982            .unwrap_or(false)
11983        {
11984            return;
11985        }
11986
11987        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11988            cx.propagate();
11989            return;
11990        }
11991
11992        let Some(row_count) = self.visible_row_count() else {
11993            return;
11994        };
11995
11996        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11997
11998        let autoscroll = if action.center_cursor {
11999            Autoscroll::center()
12000        } else {
12001            Autoscroll::fit()
12002        };
12003
12004        let text_layout_details = &self.text_layout_details(window);
12005        self.change_selections(Some(autoscroll), window, cx, |s| {
12006            s.move_with(|map, selection| {
12007                if !selection.is_empty() {
12008                    selection.goal = SelectionGoal::None;
12009                }
12010                let (cursor, goal) = movement::down_by_rows(
12011                    map,
12012                    selection.end,
12013                    row_count,
12014                    selection.goal,
12015                    false,
12016                    text_layout_details,
12017                );
12018                selection.collapse_to(cursor, goal);
12019            });
12020        });
12021    }
12022
12023    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12024        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12025        let text_layout_details = &self.text_layout_details(window);
12026        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12027            s.move_heads_with(|map, head, goal| {
12028                movement::down(map, head, goal, false, text_layout_details)
12029            })
12030        });
12031    }
12032
12033    pub fn context_menu_first(
12034        &mut self,
12035        _: &ContextMenuFirst,
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_first(self.completion_provider.as_deref(), window, cx);
12041        }
12042    }
12043
12044    pub fn context_menu_prev(
12045        &mut self,
12046        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
12052        }
12053    }
12054
12055    pub fn context_menu_next(
12056        &mut self,
12057        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), window, cx);
12063        }
12064    }
12065
12066    pub fn context_menu_last(
12067        &mut self,
12068        _: &ContextMenuLast,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12073            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12074        }
12075    }
12076
12077    pub fn move_to_previous_word_start(
12078        &mut self,
12079        _: &MoveToPreviousWordStart,
12080        window: &mut Window,
12081        cx: &mut Context<Self>,
12082    ) {
12083        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12084        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12085            s.move_cursors_with(|map, head, _| {
12086                (
12087                    movement::previous_word_start(map, head),
12088                    SelectionGoal::None,
12089                )
12090            });
12091        })
12092    }
12093
12094    pub fn move_to_previous_subword_start(
12095        &mut self,
12096        _: &MoveToPreviousSubwordStart,
12097        window: &mut Window,
12098        cx: &mut Context<Self>,
12099    ) {
12100        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12101        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12102            s.move_cursors_with(|map, head, _| {
12103                (
12104                    movement::previous_subword_start(map, head),
12105                    SelectionGoal::None,
12106                )
12107            });
12108        })
12109    }
12110
12111    pub fn select_to_previous_word_start(
12112        &mut self,
12113        _: &SelectToPreviousWordStart,
12114        window: &mut Window,
12115        cx: &mut Context<Self>,
12116    ) {
12117        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12118        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12119            s.move_heads_with(|map, head, _| {
12120                (
12121                    movement::previous_word_start(map, head),
12122                    SelectionGoal::None,
12123                )
12124            });
12125        })
12126    }
12127
12128    pub fn select_to_previous_subword_start(
12129        &mut self,
12130        _: &SelectToPreviousSubwordStart,
12131        window: &mut Window,
12132        cx: &mut Context<Self>,
12133    ) {
12134        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12135        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12136            s.move_heads_with(|map, head, _| {
12137                (
12138                    movement::previous_subword_start(map, head),
12139                    SelectionGoal::None,
12140                )
12141            });
12142        })
12143    }
12144
12145    pub fn delete_to_previous_word_start(
12146        &mut self,
12147        action: &DeleteToPreviousWordStart,
12148        window: &mut Window,
12149        cx: &mut Context<Self>,
12150    ) {
12151        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12152        self.transact(window, cx, |this, window, cx| {
12153            this.select_autoclose_pair(window, cx);
12154            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12155                s.move_with(|map, selection| {
12156                    if selection.is_empty() {
12157                        let cursor = if action.ignore_newlines {
12158                            movement::previous_word_start(map, selection.head())
12159                        } else {
12160                            movement::previous_word_start_or_newline(map, selection.head())
12161                        };
12162                        selection.set_head(cursor, SelectionGoal::None);
12163                    }
12164                });
12165            });
12166            this.insert("", window, cx);
12167        });
12168    }
12169
12170    pub fn delete_to_previous_subword_start(
12171        &mut self,
12172        _: &DeleteToPreviousSubwordStart,
12173        window: &mut Window,
12174        cx: &mut Context<Self>,
12175    ) {
12176        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12177        self.transact(window, cx, |this, window, cx| {
12178            this.select_autoclose_pair(window, cx);
12179            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12180                s.move_with(|map, selection| {
12181                    if selection.is_empty() {
12182                        let cursor = movement::previous_subword_start(map, selection.head());
12183                        selection.set_head(cursor, SelectionGoal::None);
12184                    }
12185                });
12186            });
12187            this.insert("", window, cx);
12188        });
12189    }
12190
12191    pub fn move_to_next_word_end(
12192        &mut self,
12193        _: &MoveToNextWordEnd,
12194        window: &mut Window,
12195        cx: &mut Context<Self>,
12196    ) {
12197        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12198        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12199            s.move_cursors_with(|map, head, _| {
12200                (movement::next_word_end(map, head), SelectionGoal::None)
12201            });
12202        })
12203    }
12204
12205    pub fn move_to_next_subword_end(
12206        &mut self,
12207        _: &MoveToNextSubwordEnd,
12208        window: &mut Window,
12209        cx: &mut Context<Self>,
12210    ) {
12211        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12212        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12213            s.move_cursors_with(|map, head, _| {
12214                (movement::next_subword_end(map, head), SelectionGoal::None)
12215            });
12216        })
12217    }
12218
12219    pub fn select_to_next_word_end(
12220        &mut self,
12221        _: &SelectToNextWordEnd,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12227            s.move_heads_with(|map, head, _| {
12228                (movement::next_word_end(map, head), SelectionGoal::None)
12229            });
12230        })
12231    }
12232
12233    pub fn select_to_next_subword_end(
12234        &mut self,
12235        _: &SelectToNextSubwordEnd,
12236        window: &mut Window,
12237        cx: &mut Context<Self>,
12238    ) {
12239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12240        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12241            s.move_heads_with(|map, head, _| {
12242                (movement::next_subword_end(map, head), SelectionGoal::None)
12243            });
12244        })
12245    }
12246
12247    pub fn delete_to_next_word_end(
12248        &mut self,
12249        action: &DeleteToNextWordEnd,
12250        window: &mut Window,
12251        cx: &mut Context<Self>,
12252    ) {
12253        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12254        self.transact(window, cx, |this, window, cx| {
12255            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12256                s.move_with(|map, selection| {
12257                    if selection.is_empty() {
12258                        let cursor = if action.ignore_newlines {
12259                            movement::next_word_end(map, selection.head())
12260                        } else {
12261                            movement::next_word_end_or_newline(map, selection.head())
12262                        };
12263                        selection.set_head(cursor, SelectionGoal::None);
12264                    }
12265                });
12266            });
12267            this.insert("", window, cx);
12268        });
12269    }
12270
12271    pub fn delete_to_next_subword_end(
12272        &mut self,
12273        _: &DeleteToNextSubwordEnd,
12274        window: &mut Window,
12275        cx: &mut Context<Self>,
12276    ) {
12277        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12278        self.transact(window, cx, |this, window, cx| {
12279            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12280                s.move_with(|map, selection| {
12281                    if selection.is_empty() {
12282                        let cursor = movement::next_subword_end(map, selection.head());
12283                        selection.set_head(cursor, SelectionGoal::None);
12284                    }
12285                });
12286            });
12287            this.insert("", window, cx);
12288        });
12289    }
12290
12291    pub fn move_to_beginning_of_line(
12292        &mut self,
12293        action: &MoveToBeginningOfLine,
12294        window: &mut Window,
12295        cx: &mut Context<Self>,
12296    ) {
12297        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12298        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12299            s.move_cursors_with(|map, head, _| {
12300                (
12301                    movement::indented_line_beginning(
12302                        map,
12303                        head,
12304                        action.stop_at_soft_wraps,
12305                        action.stop_at_indent,
12306                    ),
12307                    SelectionGoal::None,
12308                )
12309            });
12310        })
12311    }
12312
12313    pub fn select_to_beginning_of_line(
12314        &mut self,
12315        action: &SelectToBeginningOfLine,
12316        window: &mut Window,
12317        cx: &mut Context<Self>,
12318    ) {
12319        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12320        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12321            s.move_heads_with(|map, head, _| {
12322                (
12323                    movement::indented_line_beginning(
12324                        map,
12325                        head,
12326                        action.stop_at_soft_wraps,
12327                        action.stop_at_indent,
12328                    ),
12329                    SelectionGoal::None,
12330                )
12331            });
12332        });
12333    }
12334
12335    pub fn delete_to_beginning_of_line(
12336        &mut self,
12337        action: &DeleteToBeginningOfLine,
12338        window: &mut Window,
12339        cx: &mut Context<Self>,
12340    ) {
12341        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12342        self.transact(window, cx, |this, window, cx| {
12343            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12344                s.move_with(|_, selection| {
12345                    selection.reversed = true;
12346                });
12347            });
12348
12349            this.select_to_beginning_of_line(
12350                &SelectToBeginningOfLine {
12351                    stop_at_soft_wraps: false,
12352                    stop_at_indent: action.stop_at_indent,
12353                },
12354                window,
12355                cx,
12356            );
12357            this.backspace(&Backspace, window, cx);
12358        });
12359    }
12360
12361    pub fn move_to_end_of_line(
12362        &mut self,
12363        action: &MoveToEndOfLine,
12364        window: &mut Window,
12365        cx: &mut Context<Self>,
12366    ) {
12367        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12369            s.move_cursors_with(|map, head, _| {
12370                (
12371                    movement::line_end(map, head, action.stop_at_soft_wraps),
12372                    SelectionGoal::None,
12373                )
12374            });
12375        })
12376    }
12377
12378    pub fn select_to_end_of_line(
12379        &mut self,
12380        action: &SelectToEndOfLine,
12381        window: &mut Window,
12382        cx: &mut Context<Self>,
12383    ) {
12384        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12385        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12386            s.move_heads_with(|map, head, _| {
12387                (
12388                    movement::line_end(map, head, action.stop_at_soft_wraps),
12389                    SelectionGoal::None,
12390                )
12391            });
12392        })
12393    }
12394
12395    pub fn delete_to_end_of_line(
12396        &mut self,
12397        _: &DeleteToEndOfLine,
12398        window: &mut Window,
12399        cx: &mut Context<Self>,
12400    ) {
12401        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12402        self.transact(window, cx, |this, window, cx| {
12403            this.select_to_end_of_line(
12404                &SelectToEndOfLine {
12405                    stop_at_soft_wraps: false,
12406                },
12407                window,
12408                cx,
12409            );
12410            this.delete(&Delete, window, cx);
12411        });
12412    }
12413
12414    pub fn cut_to_end_of_line(
12415        &mut self,
12416        _: &CutToEndOfLine,
12417        window: &mut Window,
12418        cx: &mut Context<Self>,
12419    ) {
12420        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12421        self.transact(window, cx, |this, window, cx| {
12422            this.select_to_end_of_line(
12423                &SelectToEndOfLine {
12424                    stop_at_soft_wraps: false,
12425                },
12426                window,
12427                cx,
12428            );
12429            this.cut(&Cut, window, cx);
12430        });
12431    }
12432
12433    pub fn move_to_start_of_paragraph(
12434        &mut self,
12435        _: &MoveToStartOfParagraph,
12436        window: &mut Window,
12437        cx: &mut Context<Self>,
12438    ) {
12439        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12440            cx.propagate();
12441            return;
12442        }
12443        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12444        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12445            s.move_with(|map, selection| {
12446                selection.collapse_to(
12447                    movement::start_of_paragraph(map, selection.head(), 1),
12448                    SelectionGoal::None,
12449                )
12450            });
12451        })
12452    }
12453
12454    pub fn move_to_end_of_paragraph(
12455        &mut self,
12456        _: &MoveToEndOfParagraph,
12457        window: &mut Window,
12458        cx: &mut Context<Self>,
12459    ) {
12460        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12461            cx.propagate();
12462            return;
12463        }
12464        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12465        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12466            s.move_with(|map, selection| {
12467                selection.collapse_to(
12468                    movement::end_of_paragraph(map, selection.head(), 1),
12469                    SelectionGoal::None,
12470                )
12471            });
12472        })
12473    }
12474
12475    pub fn select_to_start_of_paragraph(
12476        &mut self,
12477        _: &SelectToStartOfParagraph,
12478        window: &mut Window,
12479        cx: &mut Context<Self>,
12480    ) {
12481        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12482            cx.propagate();
12483            return;
12484        }
12485        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12486        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12487            s.move_heads_with(|map, head, _| {
12488                (
12489                    movement::start_of_paragraph(map, head, 1),
12490                    SelectionGoal::None,
12491                )
12492            });
12493        })
12494    }
12495
12496    pub fn select_to_end_of_paragraph(
12497        &mut self,
12498        _: &SelectToEndOfParagraph,
12499        window: &mut Window,
12500        cx: &mut Context<Self>,
12501    ) {
12502        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12503            cx.propagate();
12504            return;
12505        }
12506        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12507        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12508            s.move_heads_with(|map, head, _| {
12509                (
12510                    movement::end_of_paragraph(map, head, 1),
12511                    SelectionGoal::None,
12512                )
12513            });
12514        })
12515    }
12516
12517    pub fn move_to_start_of_excerpt(
12518        &mut self,
12519        _: &MoveToStartOfExcerpt,
12520        window: &mut Window,
12521        cx: &mut Context<Self>,
12522    ) {
12523        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12524            cx.propagate();
12525            return;
12526        }
12527        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12528        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12529            s.move_with(|map, selection| {
12530                selection.collapse_to(
12531                    movement::start_of_excerpt(
12532                        map,
12533                        selection.head(),
12534                        workspace::searchable::Direction::Prev,
12535                    ),
12536                    SelectionGoal::None,
12537                )
12538            });
12539        })
12540    }
12541
12542    pub fn move_to_start_of_next_excerpt(
12543        &mut self,
12544        _: &MoveToStartOfNextExcerpt,
12545        window: &mut Window,
12546        cx: &mut Context<Self>,
12547    ) {
12548        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12549            cx.propagate();
12550            return;
12551        }
12552
12553        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12554            s.move_with(|map, selection| {
12555                selection.collapse_to(
12556                    movement::start_of_excerpt(
12557                        map,
12558                        selection.head(),
12559                        workspace::searchable::Direction::Next,
12560                    ),
12561                    SelectionGoal::None,
12562                )
12563            });
12564        })
12565    }
12566
12567    pub fn move_to_end_of_excerpt(
12568        &mut self,
12569        _: &MoveToEndOfExcerpt,
12570        window: &mut Window,
12571        cx: &mut Context<Self>,
12572    ) {
12573        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12574            cx.propagate();
12575            return;
12576        }
12577        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12578        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12579            s.move_with(|map, selection| {
12580                selection.collapse_to(
12581                    movement::end_of_excerpt(
12582                        map,
12583                        selection.head(),
12584                        workspace::searchable::Direction::Next,
12585                    ),
12586                    SelectionGoal::None,
12587                )
12588            });
12589        })
12590    }
12591
12592    pub fn move_to_end_of_previous_excerpt(
12593        &mut self,
12594        _: &MoveToEndOfPreviousExcerpt,
12595        window: &mut Window,
12596        cx: &mut Context<Self>,
12597    ) {
12598        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12599            cx.propagate();
12600            return;
12601        }
12602        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12603        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12604            s.move_with(|map, selection| {
12605                selection.collapse_to(
12606                    movement::end_of_excerpt(
12607                        map,
12608                        selection.head(),
12609                        workspace::searchable::Direction::Prev,
12610                    ),
12611                    SelectionGoal::None,
12612                )
12613            });
12614        })
12615    }
12616
12617    pub fn select_to_start_of_excerpt(
12618        &mut self,
12619        _: &SelectToStartOfExcerpt,
12620        window: &mut Window,
12621        cx: &mut Context<Self>,
12622    ) {
12623        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12624            cx.propagate();
12625            return;
12626        }
12627        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12628        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12629            s.move_heads_with(|map, head, _| {
12630                (
12631                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12632                    SelectionGoal::None,
12633                )
12634            });
12635        })
12636    }
12637
12638    pub fn select_to_start_of_next_excerpt(
12639        &mut self,
12640        _: &SelectToStartOfNextExcerpt,
12641        window: &mut Window,
12642        cx: &mut Context<Self>,
12643    ) {
12644        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12645            cx.propagate();
12646            return;
12647        }
12648        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12649        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12650            s.move_heads_with(|map, head, _| {
12651                (
12652                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12653                    SelectionGoal::None,
12654                )
12655            });
12656        })
12657    }
12658
12659    pub fn select_to_end_of_excerpt(
12660        &mut self,
12661        _: &SelectToEndOfExcerpt,
12662        window: &mut Window,
12663        cx: &mut Context<Self>,
12664    ) {
12665        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12666            cx.propagate();
12667            return;
12668        }
12669        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12670        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12671            s.move_heads_with(|map, head, _| {
12672                (
12673                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12674                    SelectionGoal::None,
12675                )
12676            });
12677        })
12678    }
12679
12680    pub fn select_to_end_of_previous_excerpt(
12681        &mut self,
12682        _: &SelectToEndOfPreviousExcerpt,
12683        window: &mut Window,
12684        cx: &mut Context<Self>,
12685    ) {
12686        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12687            cx.propagate();
12688            return;
12689        }
12690        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12691        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12692            s.move_heads_with(|map, head, _| {
12693                (
12694                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12695                    SelectionGoal::None,
12696                )
12697            });
12698        })
12699    }
12700
12701    pub fn move_to_beginning(
12702        &mut self,
12703        _: &MoveToBeginning,
12704        window: &mut Window,
12705        cx: &mut Context<Self>,
12706    ) {
12707        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12708            cx.propagate();
12709            return;
12710        }
12711        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12712        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12713            s.select_ranges(vec![0..0]);
12714        });
12715    }
12716
12717    pub fn select_to_beginning(
12718        &mut self,
12719        _: &SelectToBeginning,
12720        window: &mut Window,
12721        cx: &mut Context<Self>,
12722    ) {
12723        let mut selection = self.selections.last::<Point>(cx);
12724        selection.set_head(Point::zero(), SelectionGoal::None);
12725        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12726        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12727            s.select(vec![selection]);
12728        });
12729    }
12730
12731    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12732        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12733            cx.propagate();
12734            return;
12735        }
12736        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12737        let cursor = self.buffer.read(cx).read(cx).len();
12738        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12739            s.select_ranges(vec![cursor..cursor])
12740        });
12741    }
12742
12743    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12744        self.nav_history = nav_history;
12745    }
12746
12747    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12748        self.nav_history.as_ref()
12749    }
12750
12751    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12752        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12753    }
12754
12755    fn push_to_nav_history(
12756        &mut self,
12757        cursor_anchor: Anchor,
12758        new_position: Option<Point>,
12759        is_deactivate: bool,
12760        cx: &mut Context<Self>,
12761    ) {
12762        if let Some(nav_history) = self.nav_history.as_mut() {
12763            let buffer = self.buffer.read(cx).read(cx);
12764            let cursor_position = cursor_anchor.to_point(&buffer);
12765            let scroll_state = self.scroll_manager.anchor();
12766            let scroll_top_row = scroll_state.top_row(&buffer);
12767            drop(buffer);
12768
12769            if let Some(new_position) = new_position {
12770                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12771                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12772                    return;
12773                }
12774            }
12775
12776            nav_history.push(
12777                Some(NavigationData {
12778                    cursor_anchor,
12779                    cursor_position,
12780                    scroll_anchor: scroll_state,
12781                    scroll_top_row,
12782                }),
12783                cx,
12784            );
12785            cx.emit(EditorEvent::PushedToNavHistory {
12786                anchor: cursor_anchor,
12787                is_deactivate,
12788            })
12789        }
12790    }
12791
12792    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12793        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12794        let buffer = self.buffer.read(cx).snapshot(cx);
12795        let mut selection = self.selections.first::<usize>(cx);
12796        selection.set_head(buffer.len(), SelectionGoal::None);
12797        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12798            s.select(vec![selection]);
12799        });
12800    }
12801
12802    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12803        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12804        let end = self.buffer.read(cx).read(cx).len();
12805        self.change_selections(None, window, cx, |s| {
12806            s.select_ranges(vec![0..end]);
12807        });
12808    }
12809
12810    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12811        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12812        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12813        let mut selections = self.selections.all::<Point>(cx);
12814        let max_point = display_map.buffer_snapshot.max_point();
12815        for selection in &mut selections {
12816            let rows = selection.spanned_rows(true, &display_map);
12817            selection.start = Point::new(rows.start.0, 0);
12818            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12819            selection.reversed = false;
12820        }
12821        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12822            s.select(selections);
12823        });
12824    }
12825
12826    pub fn split_selection_into_lines(
12827        &mut self,
12828        _: &SplitSelectionIntoLines,
12829        window: &mut Window,
12830        cx: &mut Context<Self>,
12831    ) {
12832        let selections = self
12833            .selections
12834            .all::<Point>(cx)
12835            .into_iter()
12836            .map(|selection| selection.start..selection.end)
12837            .collect::<Vec<_>>();
12838        self.unfold_ranges(&selections, true, true, cx);
12839
12840        let mut new_selection_ranges = Vec::new();
12841        {
12842            let buffer = self.buffer.read(cx).read(cx);
12843            for selection in selections {
12844                for row in selection.start.row..selection.end.row {
12845                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12846                    new_selection_ranges.push(cursor..cursor);
12847                }
12848
12849                let is_multiline_selection = selection.start.row != selection.end.row;
12850                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12851                // so this action feels more ergonomic when paired with other selection operations
12852                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12853                if !should_skip_last {
12854                    new_selection_ranges.push(selection.end..selection.end);
12855                }
12856            }
12857        }
12858        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12859            s.select_ranges(new_selection_ranges);
12860        });
12861    }
12862
12863    pub fn add_selection_above(
12864        &mut self,
12865        _: &AddSelectionAbove,
12866        window: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        self.add_selection(true, window, cx);
12870    }
12871
12872    pub fn add_selection_below(
12873        &mut self,
12874        _: &AddSelectionBelow,
12875        window: &mut Window,
12876        cx: &mut Context<Self>,
12877    ) {
12878        self.add_selection(false, window, cx);
12879    }
12880
12881    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12882        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12883
12884        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12885        let all_selections = self.selections.all::<Point>(cx);
12886        let text_layout_details = self.text_layout_details(window);
12887
12888        let (mut columnar_selections, new_selections_to_columnarize) = {
12889            if let Some(state) = self.add_selections_state.as_ref() {
12890                let columnar_selection_ids: HashSet<_> = state
12891                    .groups
12892                    .iter()
12893                    .flat_map(|group| group.stack.iter())
12894                    .copied()
12895                    .collect();
12896
12897                all_selections
12898                    .into_iter()
12899                    .partition(|s| columnar_selection_ids.contains(&s.id))
12900            } else {
12901                (Vec::new(), all_selections)
12902            }
12903        };
12904
12905        let mut state = self
12906            .add_selections_state
12907            .take()
12908            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12909
12910        for selection in new_selections_to_columnarize {
12911            let range = selection.display_range(&display_map).sorted();
12912            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12913            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12914            let positions = start_x.min(end_x)..start_x.max(end_x);
12915            let mut stack = Vec::new();
12916            for row in range.start.row().0..=range.end.row().0 {
12917                if let Some(selection) = self.selections.build_columnar_selection(
12918                    &display_map,
12919                    DisplayRow(row),
12920                    &positions,
12921                    selection.reversed,
12922                    &text_layout_details,
12923                ) {
12924                    stack.push(selection.id);
12925                    columnar_selections.push(selection);
12926                }
12927            }
12928            if !stack.is_empty() {
12929                if above {
12930                    stack.reverse();
12931                }
12932                state.groups.push(AddSelectionsGroup { above, stack });
12933            }
12934        }
12935
12936        let mut final_selections = Vec::new();
12937        let end_row = if above {
12938            DisplayRow(0)
12939        } else {
12940            display_map.max_point().row()
12941        };
12942
12943        let mut last_added_item_per_group = HashMap::default();
12944        for group in state.groups.iter_mut() {
12945            if let Some(last_id) = group.stack.last() {
12946                last_added_item_per_group.insert(*last_id, group);
12947            }
12948        }
12949
12950        for selection in columnar_selections {
12951            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12952                if above == group.above {
12953                    let range = selection.display_range(&display_map).sorted();
12954                    debug_assert_eq!(range.start.row(), range.end.row());
12955                    let mut row = range.start.row();
12956                    let positions =
12957                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12958                            px(start)..px(end)
12959                        } else {
12960                            let start_x =
12961                                display_map.x_for_display_point(range.start, &text_layout_details);
12962                            let end_x =
12963                                display_map.x_for_display_point(range.end, &text_layout_details);
12964                            start_x.min(end_x)..start_x.max(end_x)
12965                        };
12966
12967                    let mut maybe_new_selection = None;
12968                    while row != end_row {
12969                        if above {
12970                            row.0 -= 1;
12971                        } else {
12972                            row.0 += 1;
12973                        }
12974                        if let Some(new_selection) = self.selections.build_columnar_selection(
12975                            &display_map,
12976                            row,
12977                            &positions,
12978                            selection.reversed,
12979                            &text_layout_details,
12980                        ) {
12981                            maybe_new_selection = Some(new_selection);
12982                            break;
12983                        }
12984                    }
12985
12986                    if let Some(new_selection) = maybe_new_selection {
12987                        group.stack.push(new_selection.id);
12988                        if above {
12989                            final_selections.push(new_selection);
12990                            final_selections.push(selection);
12991                        } else {
12992                            final_selections.push(selection);
12993                            final_selections.push(new_selection);
12994                        }
12995                    } else {
12996                        final_selections.push(selection);
12997                    }
12998                } else {
12999                    group.stack.pop();
13000                }
13001            } else {
13002                final_selections.push(selection);
13003            }
13004        }
13005
13006        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13007            s.select(final_selections);
13008        });
13009
13010        let final_selection_ids: HashSet<_> = self
13011            .selections
13012            .all::<Point>(cx)
13013            .iter()
13014            .map(|s| s.id)
13015            .collect();
13016        state.groups.retain_mut(|group| {
13017            // selections might get merged above so we remove invalid items from stacks
13018            group.stack.retain(|id| final_selection_ids.contains(id));
13019
13020            // single selection in stack can be treated as initial state
13021            group.stack.len() > 1
13022        });
13023
13024        if !state.groups.is_empty() {
13025            self.add_selections_state = Some(state);
13026        }
13027    }
13028
13029    fn select_match_ranges(
13030        &mut self,
13031        range: Range<usize>,
13032        reversed: bool,
13033        replace_newest: bool,
13034        auto_scroll: Option<Autoscroll>,
13035        window: &mut Window,
13036        cx: &mut Context<Editor>,
13037    ) {
13038        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13039        self.change_selections(auto_scroll, window, cx, |s| {
13040            if replace_newest {
13041                s.delete(s.newest_anchor().id);
13042            }
13043            if reversed {
13044                s.insert_range(range.end..range.start);
13045            } else {
13046                s.insert_range(range);
13047            }
13048        });
13049    }
13050
13051    pub fn select_next_match_internal(
13052        &mut self,
13053        display_map: &DisplaySnapshot,
13054        replace_newest: bool,
13055        autoscroll: Option<Autoscroll>,
13056        window: &mut Window,
13057        cx: &mut Context<Self>,
13058    ) -> Result<()> {
13059        let buffer = &display_map.buffer_snapshot;
13060        let mut selections = self.selections.all::<usize>(cx);
13061        if let Some(mut select_next_state) = self.select_next_state.take() {
13062            let query = &select_next_state.query;
13063            if !select_next_state.done {
13064                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13065                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13066                let mut next_selected_range = None;
13067
13068                let bytes_after_last_selection =
13069                    buffer.bytes_in_range(last_selection.end..buffer.len());
13070                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13071                let query_matches = query
13072                    .stream_find_iter(bytes_after_last_selection)
13073                    .map(|result| (last_selection.end, result))
13074                    .chain(
13075                        query
13076                            .stream_find_iter(bytes_before_first_selection)
13077                            .map(|result| (0, result)),
13078                    );
13079
13080                for (start_offset, query_match) in query_matches {
13081                    let query_match = query_match.unwrap(); // can only fail due to I/O
13082                    let offset_range =
13083                        start_offset + query_match.start()..start_offset + query_match.end();
13084                    let display_range = offset_range.start.to_display_point(display_map)
13085                        ..offset_range.end.to_display_point(display_map);
13086
13087                    if !select_next_state.wordwise
13088                        || (!movement::is_inside_word(display_map, display_range.start)
13089                            && !movement::is_inside_word(display_map, display_range.end))
13090                    {
13091                        // TODO: This is n^2, because we might check all the selections
13092                        if !selections
13093                            .iter()
13094                            .any(|selection| selection.range().overlaps(&offset_range))
13095                        {
13096                            next_selected_range = Some(offset_range);
13097                            break;
13098                        }
13099                    }
13100                }
13101
13102                if let Some(next_selected_range) = next_selected_range {
13103                    self.select_match_ranges(
13104                        next_selected_range,
13105                        last_selection.reversed,
13106                        replace_newest,
13107                        autoscroll,
13108                        window,
13109                        cx,
13110                    );
13111                } else {
13112                    select_next_state.done = true;
13113                }
13114            }
13115
13116            self.select_next_state = Some(select_next_state);
13117        } else {
13118            let mut only_carets = true;
13119            let mut same_text_selected = true;
13120            let mut selected_text = None;
13121
13122            let mut selections_iter = selections.iter().peekable();
13123            while let Some(selection) = selections_iter.next() {
13124                if selection.start != selection.end {
13125                    only_carets = false;
13126                }
13127
13128                if same_text_selected {
13129                    if selected_text.is_none() {
13130                        selected_text =
13131                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13132                    }
13133
13134                    if let Some(next_selection) = selections_iter.peek() {
13135                        if next_selection.range().len() == selection.range().len() {
13136                            let next_selected_text = buffer
13137                                .text_for_range(next_selection.range())
13138                                .collect::<String>();
13139                            if Some(next_selected_text) != selected_text {
13140                                same_text_selected = false;
13141                                selected_text = None;
13142                            }
13143                        } else {
13144                            same_text_selected = false;
13145                            selected_text = None;
13146                        }
13147                    }
13148                }
13149            }
13150
13151            if only_carets {
13152                for selection in &mut selections {
13153                    let word_range = movement::surrounding_word(
13154                        display_map,
13155                        selection.start.to_display_point(display_map),
13156                    );
13157                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13158                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13159                    selection.goal = SelectionGoal::None;
13160                    selection.reversed = false;
13161                    self.select_match_ranges(
13162                        selection.start..selection.end,
13163                        selection.reversed,
13164                        replace_newest,
13165                        autoscroll,
13166                        window,
13167                        cx,
13168                    );
13169                }
13170
13171                if selections.len() == 1 {
13172                    let selection = selections
13173                        .last()
13174                        .expect("ensured that there's only one selection");
13175                    let query = buffer
13176                        .text_for_range(selection.start..selection.end)
13177                        .collect::<String>();
13178                    let is_empty = query.is_empty();
13179                    let select_state = SelectNextState {
13180                        query: AhoCorasick::new(&[query])?,
13181                        wordwise: true,
13182                        done: is_empty,
13183                    };
13184                    self.select_next_state = Some(select_state);
13185                } else {
13186                    self.select_next_state = None;
13187                }
13188            } else if let Some(selected_text) = selected_text {
13189                self.select_next_state = Some(SelectNextState {
13190                    query: AhoCorasick::new(&[selected_text])?,
13191                    wordwise: false,
13192                    done: false,
13193                });
13194                self.select_next_match_internal(
13195                    display_map,
13196                    replace_newest,
13197                    autoscroll,
13198                    window,
13199                    cx,
13200                )?;
13201            }
13202        }
13203        Ok(())
13204    }
13205
13206    pub fn select_all_matches(
13207        &mut self,
13208        _action: &SelectAllMatches,
13209        window: &mut Window,
13210        cx: &mut Context<Self>,
13211    ) -> Result<()> {
13212        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13213
13214        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13215
13216        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13217        let Some(select_next_state) = self.select_next_state.as_mut() else {
13218            return Ok(());
13219        };
13220        if select_next_state.done {
13221            return Ok(());
13222        }
13223
13224        let mut new_selections = Vec::new();
13225
13226        let reversed = self.selections.oldest::<usize>(cx).reversed;
13227        let buffer = &display_map.buffer_snapshot;
13228        let query_matches = select_next_state
13229            .query
13230            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13231
13232        for query_match in query_matches.into_iter() {
13233            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13234            let offset_range = if reversed {
13235                query_match.end()..query_match.start()
13236            } else {
13237                query_match.start()..query_match.end()
13238            };
13239            let display_range = offset_range.start.to_display_point(&display_map)
13240                ..offset_range.end.to_display_point(&display_map);
13241
13242            if !select_next_state.wordwise
13243                || (!movement::is_inside_word(&display_map, display_range.start)
13244                    && !movement::is_inside_word(&display_map, display_range.end))
13245            {
13246                new_selections.push(offset_range.start..offset_range.end);
13247            }
13248        }
13249
13250        select_next_state.done = true;
13251        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13252        self.change_selections(None, window, cx, |selections| {
13253            selections.select_ranges(new_selections)
13254        });
13255
13256        Ok(())
13257    }
13258
13259    pub fn select_next(
13260        &mut self,
13261        action: &SelectNext,
13262        window: &mut Window,
13263        cx: &mut Context<Self>,
13264    ) -> Result<()> {
13265        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13266        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13267        self.select_next_match_internal(
13268            &display_map,
13269            action.replace_newest,
13270            Some(Autoscroll::newest()),
13271            window,
13272            cx,
13273        )?;
13274        Ok(())
13275    }
13276
13277    pub fn select_previous(
13278        &mut self,
13279        action: &SelectPrevious,
13280        window: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) -> Result<()> {
13283        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13284        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13285        let buffer = &display_map.buffer_snapshot;
13286        let mut selections = self.selections.all::<usize>(cx);
13287        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13288            let query = &select_prev_state.query;
13289            if !select_prev_state.done {
13290                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13291                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13292                let mut next_selected_range = None;
13293                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13294                let bytes_before_last_selection =
13295                    buffer.reversed_bytes_in_range(0..last_selection.start);
13296                let bytes_after_first_selection =
13297                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13298                let query_matches = query
13299                    .stream_find_iter(bytes_before_last_selection)
13300                    .map(|result| (last_selection.start, result))
13301                    .chain(
13302                        query
13303                            .stream_find_iter(bytes_after_first_selection)
13304                            .map(|result| (buffer.len(), result)),
13305                    );
13306                for (end_offset, query_match) in query_matches {
13307                    let query_match = query_match.unwrap(); // can only fail due to I/O
13308                    let offset_range =
13309                        end_offset - query_match.end()..end_offset - query_match.start();
13310                    let display_range = offset_range.start.to_display_point(&display_map)
13311                        ..offset_range.end.to_display_point(&display_map);
13312
13313                    if !select_prev_state.wordwise
13314                        || (!movement::is_inside_word(&display_map, display_range.start)
13315                            && !movement::is_inside_word(&display_map, display_range.end))
13316                    {
13317                        next_selected_range = Some(offset_range);
13318                        break;
13319                    }
13320                }
13321
13322                if let Some(next_selected_range) = next_selected_range {
13323                    self.select_match_ranges(
13324                        next_selected_range,
13325                        last_selection.reversed,
13326                        action.replace_newest,
13327                        Some(Autoscroll::newest()),
13328                        window,
13329                        cx,
13330                    );
13331                } else {
13332                    select_prev_state.done = true;
13333                }
13334            }
13335
13336            self.select_prev_state = Some(select_prev_state);
13337        } else {
13338            let mut only_carets = true;
13339            let mut same_text_selected = true;
13340            let mut selected_text = None;
13341
13342            let mut selections_iter = selections.iter().peekable();
13343            while let Some(selection) = selections_iter.next() {
13344                if selection.start != selection.end {
13345                    only_carets = false;
13346                }
13347
13348                if same_text_selected {
13349                    if selected_text.is_none() {
13350                        selected_text =
13351                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13352                    }
13353
13354                    if let Some(next_selection) = selections_iter.peek() {
13355                        if next_selection.range().len() == selection.range().len() {
13356                            let next_selected_text = buffer
13357                                .text_for_range(next_selection.range())
13358                                .collect::<String>();
13359                            if Some(next_selected_text) != selected_text {
13360                                same_text_selected = false;
13361                                selected_text = None;
13362                            }
13363                        } else {
13364                            same_text_selected = false;
13365                            selected_text = None;
13366                        }
13367                    }
13368                }
13369            }
13370
13371            if only_carets {
13372                for selection in &mut selections {
13373                    let word_range = movement::surrounding_word(
13374                        &display_map,
13375                        selection.start.to_display_point(&display_map),
13376                    );
13377                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13378                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13379                    selection.goal = SelectionGoal::None;
13380                    selection.reversed = false;
13381                    self.select_match_ranges(
13382                        selection.start..selection.end,
13383                        selection.reversed,
13384                        action.replace_newest,
13385                        Some(Autoscroll::newest()),
13386                        window,
13387                        cx,
13388                    );
13389                }
13390                if selections.len() == 1 {
13391                    let selection = selections
13392                        .last()
13393                        .expect("ensured that there's only one selection");
13394                    let query = buffer
13395                        .text_for_range(selection.start..selection.end)
13396                        .collect::<String>();
13397                    let is_empty = query.is_empty();
13398                    let select_state = SelectNextState {
13399                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13400                        wordwise: true,
13401                        done: is_empty,
13402                    };
13403                    self.select_prev_state = Some(select_state);
13404                } else {
13405                    self.select_prev_state = None;
13406                }
13407            } else if let Some(selected_text) = selected_text {
13408                self.select_prev_state = Some(SelectNextState {
13409                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13410                    wordwise: false,
13411                    done: false,
13412                });
13413                self.select_previous(action, window, cx)?;
13414            }
13415        }
13416        Ok(())
13417    }
13418
13419    pub fn find_next_match(
13420        &mut self,
13421        _: &FindNextMatch,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) -> Result<()> {
13425        let selections = self.selections.disjoint_anchors();
13426        match selections.first() {
13427            Some(first) if selections.len() >= 2 => {
13428                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13429                    s.select_ranges([first.range()]);
13430                });
13431            }
13432            _ => self.select_next(
13433                &SelectNext {
13434                    replace_newest: true,
13435                },
13436                window,
13437                cx,
13438            )?,
13439        }
13440        Ok(())
13441    }
13442
13443    pub fn find_previous_match(
13444        &mut self,
13445        _: &FindPreviousMatch,
13446        window: &mut Window,
13447        cx: &mut Context<Self>,
13448    ) -> Result<()> {
13449        let selections = self.selections.disjoint_anchors();
13450        match selections.last() {
13451            Some(last) if selections.len() >= 2 => {
13452                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13453                    s.select_ranges([last.range()]);
13454                });
13455            }
13456            _ => self.select_previous(
13457                &SelectPrevious {
13458                    replace_newest: true,
13459                },
13460                window,
13461                cx,
13462            )?,
13463        }
13464        Ok(())
13465    }
13466
13467    pub fn toggle_comments(
13468        &mut self,
13469        action: &ToggleComments,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        if self.read_only(cx) {
13474            return;
13475        }
13476        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13477        let text_layout_details = &self.text_layout_details(window);
13478        self.transact(window, cx, |this, window, cx| {
13479            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13480            let mut edits = Vec::new();
13481            let mut selection_edit_ranges = Vec::new();
13482            let mut last_toggled_row = None;
13483            let snapshot = this.buffer.read(cx).read(cx);
13484            let empty_str: Arc<str> = Arc::default();
13485            let mut suffixes_inserted = Vec::new();
13486            let ignore_indent = action.ignore_indent;
13487
13488            fn comment_prefix_range(
13489                snapshot: &MultiBufferSnapshot,
13490                row: MultiBufferRow,
13491                comment_prefix: &str,
13492                comment_prefix_whitespace: &str,
13493                ignore_indent: bool,
13494            ) -> Range<Point> {
13495                let indent_size = if ignore_indent {
13496                    0
13497                } else {
13498                    snapshot.indent_size_for_line(row).len
13499                };
13500
13501                let start = Point::new(row.0, indent_size);
13502
13503                let mut line_bytes = snapshot
13504                    .bytes_in_range(start..snapshot.max_point())
13505                    .flatten()
13506                    .copied();
13507
13508                // If this line currently begins with the line comment prefix, then record
13509                // the range containing the prefix.
13510                if line_bytes
13511                    .by_ref()
13512                    .take(comment_prefix.len())
13513                    .eq(comment_prefix.bytes())
13514                {
13515                    // Include any whitespace that matches the comment prefix.
13516                    let matching_whitespace_len = line_bytes
13517                        .zip(comment_prefix_whitespace.bytes())
13518                        .take_while(|(a, b)| a == b)
13519                        .count() as u32;
13520                    let end = Point::new(
13521                        start.row,
13522                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13523                    );
13524                    start..end
13525                } else {
13526                    start..start
13527                }
13528            }
13529
13530            fn comment_suffix_range(
13531                snapshot: &MultiBufferSnapshot,
13532                row: MultiBufferRow,
13533                comment_suffix: &str,
13534                comment_suffix_has_leading_space: bool,
13535            ) -> Range<Point> {
13536                let end = Point::new(row.0, snapshot.line_len(row));
13537                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13538
13539                let mut line_end_bytes = snapshot
13540                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13541                    .flatten()
13542                    .copied();
13543
13544                let leading_space_len = if suffix_start_column > 0
13545                    && line_end_bytes.next() == Some(b' ')
13546                    && comment_suffix_has_leading_space
13547                {
13548                    1
13549                } else {
13550                    0
13551                };
13552
13553                // If this line currently begins with the line comment prefix, then record
13554                // the range containing the prefix.
13555                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13556                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13557                    start..end
13558                } else {
13559                    end..end
13560                }
13561            }
13562
13563            // TODO: Handle selections that cross excerpts
13564            for selection in &mut selections {
13565                let start_column = snapshot
13566                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13567                    .len;
13568                let language = if let Some(language) =
13569                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13570                {
13571                    language
13572                } else {
13573                    continue;
13574                };
13575
13576                selection_edit_ranges.clear();
13577
13578                // If multiple selections contain a given row, avoid processing that
13579                // row more than once.
13580                let mut start_row = MultiBufferRow(selection.start.row);
13581                if last_toggled_row == Some(start_row) {
13582                    start_row = start_row.next_row();
13583                }
13584                let end_row =
13585                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13586                        MultiBufferRow(selection.end.row - 1)
13587                    } else {
13588                        MultiBufferRow(selection.end.row)
13589                    };
13590                last_toggled_row = Some(end_row);
13591
13592                if start_row > end_row {
13593                    continue;
13594                }
13595
13596                // If the language has line comments, toggle those.
13597                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13598
13599                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13600                if ignore_indent {
13601                    full_comment_prefixes = full_comment_prefixes
13602                        .into_iter()
13603                        .map(|s| Arc::from(s.trim_end()))
13604                        .collect();
13605                }
13606
13607                if !full_comment_prefixes.is_empty() {
13608                    let first_prefix = full_comment_prefixes
13609                        .first()
13610                        .expect("prefixes is non-empty");
13611                    let prefix_trimmed_lengths = full_comment_prefixes
13612                        .iter()
13613                        .map(|p| p.trim_end_matches(' ').len())
13614                        .collect::<SmallVec<[usize; 4]>>();
13615
13616                    let mut all_selection_lines_are_comments = true;
13617
13618                    for row in start_row.0..=end_row.0 {
13619                        let row = MultiBufferRow(row);
13620                        if start_row < end_row && snapshot.is_line_blank(row) {
13621                            continue;
13622                        }
13623
13624                        let prefix_range = full_comment_prefixes
13625                            .iter()
13626                            .zip(prefix_trimmed_lengths.iter().copied())
13627                            .map(|(prefix, trimmed_prefix_len)| {
13628                                comment_prefix_range(
13629                                    snapshot.deref(),
13630                                    row,
13631                                    &prefix[..trimmed_prefix_len],
13632                                    &prefix[trimmed_prefix_len..],
13633                                    ignore_indent,
13634                                )
13635                            })
13636                            .max_by_key(|range| range.end.column - range.start.column)
13637                            .expect("prefixes is non-empty");
13638
13639                        if prefix_range.is_empty() {
13640                            all_selection_lines_are_comments = false;
13641                        }
13642
13643                        selection_edit_ranges.push(prefix_range);
13644                    }
13645
13646                    if all_selection_lines_are_comments {
13647                        edits.extend(
13648                            selection_edit_ranges
13649                                .iter()
13650                                .cloned()
13651                                .map(|range| (range, empty_str.clone())),
13652                        );
13653                    } else {
13654                        let min_column = selection_edit_ranges
13655                            .iter()
13656                            .map(|range| range.start.column)
13657                            .min()
13658                            .unwrap_or(0);
13659                        edits.extend(selection_edit_ranges.iter().map(|range| {
13660                            let position = Point::new(range.start.row, min_column);
13661                            (position..position, first_prefix.clone())
13662                        }));
13663                    }
13664                } else if let Some((full_comment_prefix, comment_suffix)) =
13665                    language.block_comment_delimiters()
13666                {
13667                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13668                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13669                    let prefix_range = comment_prefix_range(
13670                        snapshot.deref(),
13671                        start_row,
13672                        comment_prefix,
13673                        comment_prefix_whitespace,
13674                        ignore_indent,
13675                    );
13676                    let suffix_range = comment_suffix_range(
13677                        snapshot.deref(),
13678                        end_row,
13679                        comment_suffix.trim_start_matches(' '),
13680                        comment_suffix.starts_with(' '),
13681                    );
13682
13683                    if prefix_range.is_empty() || suffix_range.is_empty() {
13684                        edits.push((
13685                            prefix_range.start..prefix_range.start,
13686                            full_comment_prefix.clone(),
13687                        ));
13688                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13689                        suffixes_inserted.push((end_row, comment_suffix.len()));
13690                    } else {
13691                        edits.push((prefix_range, empty_str.clone()));
13692                        edits.push((suffix_range, empty_str.clone()));
13693                    }
13694                } else {
13695                    continue;
13696                }
13697            }
13698
13699            drop(snapshot);
13700            this.buffer.update(cx, |buffer, cx| {
13701                buffer.edit(edits, None, cx);
13702            });
13703
13704            // Adjust selections so that they end before any comment suffixes that
13705            // were inserted.
13706            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13707            let mut selections = this.selections.all::<Point>(cx);
13708            let snapshot = this.buffer.read(cx).read(cx);
13709            for selection in &mut selections {
13710                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13711                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13712                        Ordering::Less => {
13713                            suffixes_inserted.next();
13714                            continue;
13715                        }
13716                        Ordering::Greater => break,
13717                        Ordering::Equal => {
13718                            if selection.end.column == snapshot.line_len(row) {
13719                                if selection.is_empty() {
13720                                    selection.start.column -= suffix_len as u32;
13721                                }
13722                                selection.end.column -= suffix_len as u32;
13723                            }
13724                            break;
13725                        }
13726                    }
13727                }
13728            }
13729
13730            drop(snapshot);
13731            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13732                s.select(selections)
13733            });
13734
13735            let selections = this.selections.all::<Point>(cx);
13736            let selections_on_single_row = selections.windows(2).all(|selections| {
13737                selections[0].start.row == selections[1].start.row
13738                    && selections[0].end.row == selections[1].end.row
13739                    && selections[0].start.row == selections[0].end.row
13740            });
13741            let selections_selecting = selections
13742                .iter()
13743                .any(|selection| selection.start != selection.end);
13744            let advance_downwards = action.advance_downwards
13745                && selections_on_single_row
13746                && !selections_selecting
13747                && !matches!(this.mode, EditorMode::SingleLine { .. });
13748
13749            if advance_downwards {
13750                let snapshot = this.buffer.read(cx).snapshot(cx);
13751
13752                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13753                    s.move_cursors_with(|display_snapshot, display_point, _| {
13754                        let mut point = display_point.to_point(display_snapshot);
13755                        point.row += 1;
13756                        point = snapshot.clip_point(point, Bias::Left);
13757                        let display_point = point.to_display_point(display_snapshot);
13758                        let goal = SelectionGoal::HorizontalPosition(
13759                            display_snapshot
13760                                .x_for_display_point(display_point, text_layout_details)
13761                                .into(),
13762                        );
13763                        (display_point, goal)
13764                    })
13765                });
13766            }
13767        });
13768    }
13769
13770    pub fn select_enclosing_symbol(
13771        &mut self,
13772        _: &SelectEnclosingSymbol,
13773        window: &mut Window,
13774        cx: &mut Context<Self>,
13775    ) {
13776        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13777
13778        let buffer = self.buffer.read(cx).snapshot(cx);
13779        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13780
13781        fn update_selection(
13782            selection: &Selection<usize>,
13783            buffer_snap: &MultiBufferSnapshot,
13784        ) -> Option<Selection<usize>> {
13785            let cursor = selection.head();
13786            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13787            for symbol in symbols.iter().rev() {
13788                let start = symbol.range.start.to_offset(buffer_snap);
13789                let end = symbol.range.end.to_offset(buffer_snap);
13790                let new_range = start..end;
13791                if start < selection.start || end > selection.end {
13792                    return Some(Selection {
13793                        id: selection.id,
13794                        start: new_range.start,
13795                        end: new_range.end,
13796                        goal: SelectionGoal::None,
13797                        reversed: selection.reversed,
13798                    });
13799                }
13800            }
13801            None
13802        }
13803
13804        let mut selected_larger_symbol = false;
13805        let new_selections = old_selections
13806            .iter()
13807            .map(|selection| match update_selection(selection, &buffer) {
13808                Some(new_selection) => {
13809                    if new_selection.range() != selection.range() {
13810                        selected_larger_symbol = true;
13811                    }
13812                    new_selection
13813                }
13814                None => selection.clone(),
13815            })
13816            .collect::<Vec<_>>();
13817
13818        if selected_larger_symbol {
13819            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13820                s.select(new_selections);
13821            });
13822        }
13823    }
13824
13825    pub fn select_larger_syntax_node(
13826        &mut self,
13827        _: &SelectLargerSyntaxNode,
13828        window: &mut Window,
13829        cx: &mut Context<Self>,
13830    ) {
13831        let Some(visible_row_count) = self.visible_row_count() else {
13832            return;
13833        };
13834        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13835        if old_selections.is_empty() {
13836            return;
13837        }
13838
13839        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13840
13841        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13842        let buffer = self.buffer.read(cx).snapshot(cx);
13843
13844        let mut selected_larger_node = false;
13845        let mut new_selections = old_selections
13846            .iter()
13847            .map(|selection| {
13848                let old_range = selection.start..selection.end;
13849
13850                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13851                    // manually select word at selection
13852                    if ["string_content", "inline"].contains(&node.kind()) {
13853                        let word_range = {
13854                            let display_point = buffer
13855                                .offset_to_point(old_range.start)
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                        // ignore if word is already selected
13863                        if !word_range.is_empty() && old_range != word_range {
13864                            let last_word_range = {
13865                                let display_point = buffer
13866                                    .offset_to_point(old_range.end)
13867                                    .to_display_point(&display_map);
13868                                let Range { start, end } =
13869                                    movement::surrounding_word(&display_map, display_point);
13870                                start.to_point(&display_map).to_offset(&buffer)
13871                                    ..end.to_point(&display_map).to_offset(&buffer)
13872                            };
13873                            // only select word if start and end point belongs to same word
13874                            if word_range == last_word_range {
13875                                selected_larger_node = true;
13876                                return Selection {
13877                                    id: selection.id,
13878                                    start: word_range.start,
13879                                    end: word_range.end,
13880                                    goal: SelectionGoal::None,
13881                                    reversed: selection.reversed,
13882                                };
13883                            }
13884                        }
13885                    }
13886                }
13887
13888                let mut new_range = old_range.clone();
13889                while let Some((_node, containing_range)) =
13890                    buffer.syntax_ancestor(new_range.clone())
13891                {
13892                    new_range = match containing_range {
13893                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13894                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13895                    };
13896                    if !display_map.intersects_fold(new_range.start)
13897                        && !display_map.intersects_fold(new_range.end)
13898                    {
13899                        break;
13900                    }
13901                }
13902
13903                selected_larger_node |= new_range != old_range;
13904                Selection {
13905                    id: selection.id,
13906                    start: new_range.start,
13907                    end: new_range.end,
13908                    goal: SelectionGoal::None,
13909                    reversed: selection.reversed,
13910                }
13911            })
13912            .collect::<Vec<_>>();
13913
13914        if !selected_larger_node {
13915            return; // don't put this call in the history
13916        }
13917
13918        // scroll based on transformation done to the last selection created by the user
13919        let (last_old, last_new) = old_selections
13920            .last()
13921            .zip(new_selections.last().cloned())
13922            .expect("old_selections isn't empty");
13923
13924        // revert selection
13925        let is_selection_reversed = {
13926            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13927            new_selections.last_mut().expect("checked above").reversed =
13928                should_newest_selection_be_reversed;
13929            should_newest_selection_be_reversed
13930        };
13931
13932        if selected_larger_node {
13933            self.select_syntax_node_history.disable_clearing = true;
13934            self.change_selections(None, window, cx, |s| {
13935                s.select(new_selections.clone());
13936            });
13937            self.select_syntax_node_history.disable_clearing = false;
13938        }
13939
13940        let start_row = last_new.start.to_display_point(&display_map).row().0;
13941        let end_row = last_new.end.to_display_point(&display_map).row().0;
13942        let selection_height = end_row - start_row + 1;
13943        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13944
13945        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13946        let scroll_behavior = if fits_on_the_screen {
13947            self.request_autoscroll(Autoscroll::fit(), cx);
13948            SelectSyntaxNodeScrollBehavior::FitSelection
13949        } else if is_selection_reversed {
13950            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13951            SelectSyntaxNodeScrollBehavior::CursorTop
13952        } else {
13953            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13954            SelectSyntaxNodeScrollBehavior::CursorBottom
13955        };
13956
13957        self.select_syntax_node_history.push((
13958            old_selections,
13959            scroll_behavior,
13960            is_selection_reversed,
13961        ));
13962    }
13963
13964    pub fn select_smaller_syntax_node(
13965        &mut self,
13966        _: &SelectSmallerSyntaxNode,
13967        window: &mut Window,
13968        cx: &mut Context<Self>,
13969    ) {
13970        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13971
13972        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13973            self.select_syntax_node_history.pop()
13974        {
13975            if let Some(selection) = selections.last_mut() {
13976                selection.reversed = is_selection_reversed;
13977            }
13978
13979            self.select_syntax_node_history.disable_clearing = true;
13980            self.change_selections(None, window, cx, |s| {
13981                s.select(selections.to_vec());
13982            });
13983            self.select_syntax_node_history.disable_clearing = false;
13984
13985            match scroll_behavior {
13986                SelectSyntaxNodeScrollBehavior::CursorTop => {
13987                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13988                }
13989                SelectSyntaxNodeScrollBehavior::FitSelection => {
13990                    self.request_autoscroll(Autoscroll::fit(), cx);
13991                }
13992                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13993                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13994                }
13995            }
13996        }
13997    }
13998
13999    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14000        if !EditorSettings::get_global(cx).gutter.runnables {
14001            self.clear_tasks();
14002            return Task::ready(());
14003        }
14004        let project = self.project.as_ref().map(Entity::downgrade);
14005        let task_sources = self.lsp_task_sources(cx);
14006        let multi_buffer = self.buffer.downgrade();
14007        cx.spawn_in(window, async move |editor, cx| {
14008            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14009            let Some(project) = project.and_then(|p| p.upgrade()) else {
14010                return;
14011            };
14012            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14013                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14014            }) else {
14015                return;
14016            };
14017
14018            let hide_runnables = project
14019                .update(cx, |project, cx| {
14020                    // Do not display any test indicators in non-dev server remote projects.
14021                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14022                })
14023                .unwrap_or(true);
14024            if hide_runnables {
14025                return;
14026            }
14027            let new_rows =
14028                cx.background_spawn({
14029                    let snapshot = display_snapshot.clone();
14030                    async move {
14031                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14032                    }
14033                })
14034                    .await;
14035            let Ok(lsp_tasks) =
14036                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14037            else {
14038                return;
14039            };
14040            let lsp_tasks = lsp_tasks.await;
14041
14042            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14043                lsp_tasks
14044                    .into_iter()
14045                    .flat_map(|(kind, tasks)| {
14046                        tasks.into_iter().filter_map(move |(location, task)| {
14047                            Some((kind.clone(), location?, task))
14048                        })
14049                    })
14050                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14051                        let buffer = location.target.buffer;
14052                        let buffer_snapshot = buffer.read(cx).snapshot();
14053                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14054                            |(excerpt_id, snapshot, _)| {
14055                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14056                                    display_snapshot
14057                                        .buffer_snapshot
14058                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14059                                } else {
14060                                    None
14061                                }
14062                            },
14063                        );
14064                        if let Some(offset) = offset {
14065                            let task_buffer_range =
14066                                location.target.range.to_point(&buffer_snapshot);
14067                            let context_buffer_range =
14068                                task_buffer_range.to_offset(&buffer_snapshot);
14069                            let context_range = BufferOffset(context_buffer_range.start)
14070                                ..BufferOffset(context_buffer_range.end);
14071
14072                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14073                                .or_insert_with(|| RunnableTasks {
14074                                    templates: Vec::new(),
14075                                    offset,
14076                                    column: task_buffer_range.start.column,
14077                                    extra_variables: HashMap::default(),
14078                                    context_range,
14079                                })
14080                                .templates
14081                                .push((kind, task.original_task().clone()));
14082                        }
14083
14084                        acc
14085                    })
14086            }) else {
14087                return;
14088            };
14089
14090            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14091                buffer.language_settings(cx).tasks.prefer_lsp
14092            }) else {
14093                return;
14094            };
14095
14096            let rows = Self::runnable_rows(
14097                project,
14098                display_snapshot,
14099                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14100                new_rows,
14101                cx.clone(),
14102            )
14103            .await;
14104            editor
14105                .update(cx, |editor, _| {
14106                    editor.clear_tasks();
14107                    for (key, mut value) in rows {
14108                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14109                            value.templates.extend(lsp_tasks.templates);
14110                        }
14111
14112                        editor.insert_tasks(key, value);
14113                    }
14114                    for (key, value) in lsp_tasks_by_rows {
14115                        editor.insert_tasks(key, value);
14116                    }
14117                })
14118                .ok();
14119        })
14120    }
14121    fn fetch_runnable_ranges(
14122        snapshot: &DisplaySnapshot,
14123        range: Range<Anchor>,
14124    ) -> Vec<language::RunnableRange> {
14125        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14126    }
14127
14128    fn runnable_rows(
14129        project: Entity<Project>,
14130        snapshot: DisplaySnapshot,
14131        prefer_lsp: bool,
14132        runnable_ranges: Vec<RunnableRange>,
14133        cx: AsyncWindowContext,
14134    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14135        cx.spawn(async move |cx| {
14136            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14137            for mut runnable in runnable_ranges {
14138                let Some(tasks) = cx
14139                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14140                    .ok()
14141                else {
14142                    continue;
14143                };
14144                let mut tasks = tasks.await;
14145
14146                if prefer_lsp {
14147                    tasks.retain(|(task_kind, _)| {
14148                        !matches!(task_kind, TaskSourceKind::Language { .. })
14149                    });
14150                }
14151                if tasks.is_empty() {
14152                    continue;
14153                }
14154
14155                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14156                let Some(row) = snapshot
14157                    .buffer_snapshot
14158                    .buffer_line_for_row(MultiBufferRow(point.row))
14159                    .map(|(_, range)| range.start.row)
14160                else {
14161                    continue;
14162                };
14163
14164                let context_range =
14165                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14166                runnable_rows.push((
14167                    (runnable.buffer_id, row),
14168                    RunnableTasks {
14169                        templates: tasks,
14170                        offset: snapshot
14171                            .buffer_snapshot
14172                            .anchor_before(runnable.run_range.start),
14173                        context_range,
14174                        column: point.column,
14175                        extra_variables: runnable.extra_captures,
14176                    },
14177                ));
14178            }
14179            runnable_rows
14180        })
14181    }
14182
14183    fn templates_with_tags(
14184        project: &Entity<Project>,
14185        runnable: &mut Runnable,
14186        cx: &mut App,
14187    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14188        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14189            let (worktree_id, file) = project
14190                .buffer_for_id(runnable.buffer, cx)
14191                .and_then(|buffer| buffer.read(cx).file())
14192                .map(|file| (file.worktree_id(cx), file.clone()))
14193                .unzip();
14194
14195            (
14196                project.task_store().read(cx).task_inventory().cloned(),
14197                worktree_id,
14198                file,
14199            )
14200        });
14201
14202        let tags = mem::take(&mut runnable.tags);
14203        let language = runnable.language.clone();
14204        cx.spawn(async move |cx| {
14205            let mut templates_with_tags = Vec::new();
14206            if let Some(inventory) = inventory {
14207                for RunnableTag(tag) in tags {
14208                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14209                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14210                    }) else {
14211                        return templates_with_tags;
14212                    };
14213                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14214                        move |(_, template)| {
14215                            template.tags.iter().any(|source_tag| source_tag == &tag)
14216                        },
14217                    ));
14218                }
14219            }
14220            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14221
14222            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14223                // Strongest source wins; if we have worktree tag binding, prefer that to
14224                // global and language bindings;
14225                // if we have a global binding, prefer that to language binding.
14226                let first_mismatch = templates_with_tags
14227                    .iter()
14228                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14229                if let Some(index) = first_mismatch {
14230                    templates_with_tags.truncate(index);
14231                }
14232            }
14233
14234            templates_with_tags
14235        })
14236    }
14237
14238    pub fn move_to_enclosing_bracket(
14239        &mut self,
14240        _: &MoveToEnclosingBracket,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) {
14244        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14245        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14246            s.move_offsets_with(|snapshot, selection| {
14247                let Some(enclosing_bracket_ranges) =
14248                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14249                else {
14250                    return;
14251                };
14252
14253                let mut best_length = usize::MAX;
14254                let mut best_inside = false;
14255                let mut best_in_bracket_range = false;
14256                let mut best_destination = None;
14257                for (open, close) in enclosing_bracket_ranges {
14258                    let close = close.to_inclusive();
14259                    let length = close.end() - open.start;
14260                    let inside = selection.start >= open.end && selection.end <= *close.start();
14261                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14262                        || close.contains(&selection.head());
14263
14264                    // If best is next to a bracket and current isn't, skip
14265                    if !in_bracket_range && best_in_bracket_range {
14266                        continue;
14267                    }
14268
14269                    // Prefer smaller lengths unless best is inside and current isn't
14270                    if length > best_length && (best_inside || !inside) {
14271                        continue;
14272                    }
14273
14274                    best_length = length;
14275                    best_inside = inside;
14276                    best_in_bracket_range = in_bracket_range;
14277                    best_destination = Some(
14278                        if close.contains(&selection.start) && close.contains(&selection.end) {
14279                            if inside { open.end } else { open.start }
14280                        } else if inside {
14281                            *close.start()
14282                        } else {
14283                            *close.end()
14284                        },
14285                    );
14286                }
14287
14288                if let Some(destination) = best_destination {
14289                    selection.collapse_to(destination, SelectionGoal::None);
14290                }
14291            })
14292        });
14293    }
14294
14295    pub fn undo_selection(
14296        &mut self,
14297        _: &UndoSelection,
14298        window: &mut Window,
14299        cx: &mut Context<Self>,
14300    ) {
14301        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14302        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14303            self.selection_history.mode = SelectionHistoryMode::Undoing;
14304            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14305                this.end_selection(window, cx);
14306                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14307                    s.select_anchors(entry.selections.to_vec())
14308                });
14309            });
14310            self.selection_history.mode = SelectionHistoryMode::Normal;
14311
14312            self.select_next_state = entry.select_next_state;
14313            self.select_prev_state = entry.select_prev_state;
14314            self.add_selections_state = entry.add_selections_state;
14315        }
14316    }
14317
14318    pub fn redo_selection(
14319        &mut self,
14320        _: &RedoSelection,
14321        window: &mut Window,
14322        cx: &mut Context<Self>,
14323    ) {
14324        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14325        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14326            self.selection_history.mode = SelectionHistoryMode::Redoing;
14327            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14328                this.end_selection(window, cx);
14329                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14330                    s.select_anchors(entry.selections.to_vec())
14331                });
14332            });
14333            self.selection_history.mode = SelectionHistoryMode::Normal;
14334
14335            self.select_next_state = entry.select_next_state;
14336            self.select_prev_state = entry.select_prev_state;
14337            self.add_selections_state = entry.add_selections_state;
14338        }
14339    }
14340
14341    pub fn expand_excerpts(
14342        &mut self,
14343        action: &ExpandExcerpts,
14344        _: &mut Window,
14345        cx: &mut Context<Self>,
14346    ) {
14347        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14348    }
14349
14350    pub fn expand_excerpts_down(
14351        &mut self,
14352        action: &ExpandExcerptsDown,
14353        _: &mut Window,
14354        cx: &mut Context<Self>,
14355    ) {
14356        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14357    }
14358
14359    pub fn expand_excerpts_up(
14360        &mut self,
14361        action: &ExpandExcerptsUp,
14362        _: &mut Window,
14363        cx: &mut Context<Self>,
14364    ) {
14365        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14366    }
14367
14368    pub fn expand_excerpts_for_direction(
14369        &mut self,
14370        lines: u32,
14371        direction: ExpandExcerptDirection,
14372
14373        cx: &mut Context<Self>,
14374    ) {
14375        let selections = self.selections.disjoint_anchors();
14376
14377        let lines = if lines == 0 {
14378            EditorSettings::get_global(cx).expand_excerpt_lines
14379        } else {
14380            lines
14381        };
14382
14383        self.buffer.update(cx, |buffer, cx| {
14384            let snapshot = buffer.snapshot(cx);
14385            let mut excerpt_ids = selections
14386                .iter()
14387                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14388                .collect::<Vec<_>>();
14389            excerpt_ids.sort();
14390            excerpt_ids.dedup();
14391            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14392        })
14393    }
14394
14395    pub fn expand_excerpt(
14396        &mut self,
14397        excerpt: ExcerptId,
14398        direction: ExpandExcerptDirection,
14399        window: &mut Window,
14400        cx: &mut Context<Self>,
14401    ) {
14402        let current_scroll_position = self.scroll_position(cx);
14403        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14404        let mut should_scroll_up = false;
14405
14406        if direction == ExpandExcerptDirection::Down {
14407            let multi_buffer = self.buffer.read(cx);
14408            let snapshot = multi_buffer.snapshot(cx);
14409            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14410                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14411                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14412                        let buffer_snapshot = buffer.read(cx).snapshot();
14413                        let excerpt_end_row =
14414                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14415                        let last_row = buffer_snapshot.max_point().row;
14416                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14417                        should_scroll_up = lines_below >= lines_to_expand;
14418                    }
14419                }
14420            }
14421        }
14422
14423        self.buffer.update(cx, |buffer, cx| {
14424            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14425        });
14426
14427        if should_scroll_up {
14428            let new_scroll_position =
14429                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14430            self.set_scroll_position(new_scroll_position, window, cx);
14431        }
14432    }
14433
14434    pub fn go_to_singleton_buffer_point(
14435        &mut self,
14436        point: Point,
14437        window: &mut Window,
14438        cx: &mut Context<Self>,
14439    ) {
14440        self.go_to_singleton_buffer_range(point..point, window, cx);
14441    }
14442
14443    pub fn go_to_singleton_buffer_range(
14444        &mut self,
14445        range: Range<Point>,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) {
14449        let multibuffer = self.buffer().read(cx);
14450        let Some(buffer) = multibuffer.as_singleton() else {
14451            return;
14452        };
14453        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14454            return;
14455        };
14456        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14457            return;
14458        };
14459        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14460            s.select_anchor_ranges([start..end])
14461        });
14462    }
14463
14464    pub fn go_to_diagnostic(
14465        &mut self,
14466        _: &GoToDiagnostic,
14467        window: &mut Window,
14468        cx: &mut Context<Self>,
14469    ) {
14470        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14471        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14472    }
14473
14474    pub fn go_to_prev_diagnostic(
14475        &mut self,
14476        _: &GoToPreviousDiagnostic,
14477        window: &mut Window,
14478        cx: &mut Context<Self>,
14479    ) {
14480        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14481        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14482    }
14483
14484    pub fn go_to_diagnostic_impl(
14485        &mut self,
14486        direction: Direction,
14487        window: &mut Window,
14488        cx: &mut Context<Self>,
14489    ) {
14490        let buffer = self.buffer.read(cx).snapshot(cx);
14491        let selection = self.selections.newest::<usize>(cx);
14492
14493        let mut active_group_id = None;
14494        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14495            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14496                active_group_id = Some(active_group.group_id);
14497            }
14498        }
14499
14500        fn filtered(
14501            snapshot: EditorSnapshot,
14502            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14503        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14504            diagnostics
14505                .filter(|entry| entry.range.start != entry.range.end)
14506                .filter(|entry| !entry.diagnostic.is_unnecessary)
14507                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14508        }
14509
14510        let snapshot = self.snapshot(window, cx);
14511        let before = filtered(
14512            snapshot.clone(),
14513            buffer
14514                .diagnostics_in_range(0..selection.start)
14515                .filter(|entry| entry.range.start <= selection.start),
14516        );
14517        let after = filtered(
14518            snapshot,
14519            buffer
14520                .diagnostics_in_range(selection.start..buffer.len())
14521                .filter(|entry| entry.range.start >= selection.start),
14522        );
14523
14524        let mut found: Option<DiagnosticEntry<usize>> = None;
14525        if direction == Direction::Prev {
14526            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14527            {
14528                for diagnostic in prev_diagnostics.into_iter().rev() {
14529                    if diagnostic.range.start != selection.start
14530                        || active_group_id
14531                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14532                    {
14533                        found = Some(diagnostic);
14534                        break 'outer;
14535                    }
14536                }
14537            }
14538        } else {
14539            for diagnostic in after.chain(before) {
14540                if diagnostic.range.start != selection.start
14541                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14542                {
14543                    found = Some(diagnostic);
14544                    break;
14545                }
14546            }
14547        }
14548        let Some(next_diagnostic) = found else {
14549            return;
14550        };
14551
14552        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14553            return;
14554        };
14555        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14556            s.select_ranges(vec![
14557                next_diagnostic.range.start..next_diagnostic.range.start,
14558            ])
14559        });
14560        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14561        self.refresh_inline_completion(false, true, window, cx);
14562    }
14563
14564    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14565        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14566        let snapshot = self.snapshot(window, cx);
14567        let selection = self.selections.newest::<Point>(cx);
14568        self.go_to_hunk_before_or_after_position(
14569            &snapshot,
14570            selection.head(),
14571            Direction::Next,
14572            window,
14573            cx,
14574        );
14575    }
14576
14577    pub fn go_to_hunk_before_or_after_position(
14578        &mut self,
14579        snapshot: &EditorSnapshot,
14580        position: Point,
14581        direction: Direction,
14582        window: &mut Window,
14583        cx: &mut Context<Editor>,
14584    ) {
14585        let row = if direction == Direction::Next {
14586            self.hunk_after_position(snapshot, position)
14587                .map(|hunk| hunk.row_range.start)
14588        } else {
14589            self.hunk_before_position(snapshot, position)
14590        };
14591
14592        if let Some(row) = row {
14593            let destination = Point::new(row.0, 0);
14594            let autoscroll = Autoscroll::center();
14595
14596            self.unfold_ranges(&[destination..destination], false, false, cx);
14597            self.change_selections(Some(autoscroll), window, cx, |s| {
14598                s.select_ranges([destination..destination]);
14599            });
14600        }
14601    }
14602
14603    fn hunk_after_position(
14604        &mut self,
14605        snapshot: &EditorSnapshot,
14606        position: Point,
14607    ) -> Option<MultiBufferDiffHunk> {
14608        snapshot
14609            .buffer_snapshot
14610            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14611            .find(|hunk| hunk.row_range.start.0 > position.row)
14612            .or_else(|| {
14613                snapshot
14614                    .buffer_snapshot
14615                    .diff_hunks_in_range(Point::zero()..position)
14616                    .find(|hunk| hunk.row_range.end.0 < position.row)
14617            })
14618    }
14619
14620    fn go_to_prev_hunk(
14621        &mut self,
14622        _: &GoToPreviousHunk,
14623        window: &mut Window,
14624        cx: &mut Context<Self>,
14625    ) {
14626        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14627        let snapshot = self.snapshot(window, cx);
14628        let selection = self.selections.newest::<Point>(cx);
14629        self.go_to_hunk_before_or_after_position(
14630            &snapshot,
14631            selection.head(),
14632            Direction::Prev,
14633            window,
14634            cx,
14635        );
14636    }
14637
14638    fn hunk_before_position(
14639        &mut self,
14640        snapshot: &EditorSnapshot,
14641        position: Point,
14642    ) -> Option<MultiBufferRow> {
14643        snapshot
14644            .buffer_snapshot
14645            .diff_hunk_before(position)
14646            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14647    }
14648
14649    fn go_to_next_change(
14650        &mut self,
14651        _: &GoToNextChange,
14652        window: &mut Window,
14653        cx: &mut Context<Self>,
14654    ) {
14655        if let Some(selections) = self
14656            .change_list
14657            .next_change(1, Direction::Next)
14658            .map(|s| s.to_vec())
14659        {
14660            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14661                let map = s.display_map();
14662                s.select_display_ranges(selections.iter().map(|a| {
14663                    let point = a.to_display_point(&map);
14664                    point..point
14665                }))
14666            })
14667        }
14668    }
14669
14670    fn go_to_previous_change(
14671        &mut self,
14672        _: &GoToPreviousChange,
14673        window: &mut Window,
14674        cx: &mut Context<Self>,
14675    ) {
14676        if let Some(selections) = self
14677            .change_list
14678            .next_change(1, Direction::Prev)
14679            .map(|s| s.to_vec())
14680        {
14681            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14682                let map = s.display_map();
14683                s.select_display_ranges(selections.iter().map(|a| {
14684                    let point = a.to_display_point(&map);
14685                    point..point
14686                }))
14687            })
14688        }
14689    }
14690
14691    fn go_to_line<T: 'static>(
14692        &mut self,
14693        position: Anchor,
14694        highlight_color: Option<Hsla>,
14695        window: &mut Window,
14696        cx: &mut Context<Self>,
14697    ) {
14698        let snapshot = self.snapshot(window, cx).display_snapshot;
14699        let position = position.to_point(&snapshot.buffer_snapshot);
14700        let start = snapshot
14701            .buffer_snapshot
14702            .clip_point(Point::new(position.row, 0), Bias::Left);
14703        let end = start + Point::new(1, 0);
14704        let start = snapshot.buffer_snapshot.anchor_before(start);
14705        let end = snapshot.buffer_snapshot.anchor_before(end);
14706
14707        self.highlight_rows::<T>(
14708            start..end,
14709            highlight_color
14710                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14711            Default::default(),
14712            cx,
14713        );
14714
14715        if self.buffer.read(cx).is_singleton() {
14716            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14717        }
14718    }
14719
14720    pub fn go_to_definition(
14721        &mut self,
14722        _: &GoToDefinition,
14723        window: &mut Window,
14724        cx: &mut Context<Self>,
14725    ) -> Task<Result<Navigated>> {
14726        let definition =
14727            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14728        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14729        cx.spawn_in(window, async move |editor, cx| {
14730            if definition.await? == Navigated::Yes {
14731                return Ok(Navigated::Yes);
14732            }
14733            match fallback_strategy {
14734                GoToDefinitionFallback::None => Ok(Navigated::No),
14735                GoToDefinitionFallback::FindAllReferences => {
14736                    match editor.update_in(cx, |editor, window, cx| {
14737                        editor.find_all_references(&FindAllReferences, window, cx)
14738                    })? {
14739                        Some(references) => references.await,
14740                        None => Ok(Navigated::No),
14741                    }
14742                }
14743            }
14744        })
14745    }
14746
14747    pub fn go_to_declaration(
14748        &mut self,
14749        _: &GoToDeclaration,
14750        window: &mut Window,
14751        cx: &mut Context<Self>,
14752    ) -> Task<Result<Navigated>> {
14753        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14754    }
14755
14756    pub fn go_to_declaration_split(
14757        &mut self,
14758        _: &GoToDeclaration,
14759        window: &mut Window,
14760        cx: &mut Context<Self>,
14761    ) -> Task<Result<Navigated>> {
14762        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14763    }
14764
14765    pub fn go_to_implementation(
14766        &mut self,
14767        _: &GoToImplementation,
14768        window: &mut Window,
14769        cx: &mut Context<Self>,
14770    ) -> Task<Result<Navigated>> {
14771        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14772    }
14773
14774    pub fn go_to_implementation_split(
14775        &mut self,
14776        _: &GoToImplementationSplit,
14777        window: &mut Window,
14778        cx: &mut Context<Self>,
14779    ) -> Task<Result<Navigated>> {
14780        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14781    }
14782
14783    pub fn go_to_type_definition(
14784        &mut self,
14785        _: &GoToTypeDefinition,
14786        window: &mut Window,
14787        cx: &mut Context<Self>,
14788    ) -> Task<Result<Navigated>> {
14789        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14790    }
14791
14792    pub fn go_to_definition_split(
14793        &mut self,
14794        _: &GoToDefinitionSplit,
14795        window: &mut Window,
14796        cx: &mut Context<Self>,
14797    ) -> Task<Result<Navigated>> {
14798        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14799    }
14800
14801    pub fn go_to_type_definition_split(
14802        &mut self,
14803        _: &GoToTypeDefinitionSplit,
14804        window: &mut Window,
14805        cx: &mut Context<Self>,
14806    ) -> Task<Result<Navigated>> {
14807        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14808    }
14809
14810    fn go_to_definition_of_kind(
14811        &mut self,
14812        kind: GotoDefinitionKind,
14813        split: bool,
14814        window: &mut Window,
14815        cx: &mut Context<Self>,
14816    ) -> Task<Result<Navigated>> {
14817        let Some(provider) = self.semantics_provider.clone() else {
14818            return Task::ready(Ok(Navigated::No));
14819        };
14820        let head = self.selections.newest::<usize>(cx).head();
14821        let buffer = self.buffer.read(cx);
14822        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14823            text_anchor
14824        } else {
14825            return Task::ready(Ok(Navigated::No));
14826        };
14827
14828        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14829            return Task::ready(Ok(Navigated::No));
14830        };
14831
14832        cx.spawn_in(window, async move |editor, cx| {
14833            let definitions = definitions.await?;
14834            let navigated = editor
14835                .update_in(cx, |editor, window, cx| {
14836                    editor.navigate_to_hover_links(
14837                        Some(kind),
14838                        definitions
14839                            .into_iter()
14840                            .filter(|location| {
14841                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14842                            })
14843                            .map(HoverLink::Text)
14844                            .collect::<Vec<_>>(),
14845                        split,
14846                        window,
14847                        cx,
14848                    )
14849                })?
14850                .await?;
14851            anyhow::Ok(navigated)
14852        })
14853    }
14854
14855    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14856        let selection = self.selections.newest_anchor();
14857        let head = selection.head();
14858        let tail = selection.tail();
14859
14860        let Some((buffer, start_position)) =
14861            self.buffer.read(cx).text_anchor_for_position(head, cx)
14862        else {
14863            return;
14864        };
14865
14866        let end_position = if head != tail {
14867            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14868                return;
14869            };
14870            Some(pos)
14871        } else {
14872            None
14873        };
14874
14875        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14876            let url = if let Some(end_pos) = end_position {
14877                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14878            } else {
14879                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14880            };
14881
14882            if let Some(url) = url {
14883                editor.update(cx, |_, cx| {
14884                    cx.open_url(&url);
14885                })
14886            } else {
14887                Ok(())
14888            }
14889        });
14890
14891        url_finder.detach();
14892    }
14893
14894    pub fn open_selected_filename(
14895        &mut self,
14896        _: &OpenSelectedFilename,
14897        window: &mut Window,
14898        cx: &mut Context<Self>,
14899    ) {
14900        let Some(workspace) = self.workspace() else {
14901            return;
14902        };
14903
14904        let position = self.selections.newest_anchor().head();
14905
14906        let Some((buffer, buffer_position)) =
14907            self.buffer.read(cx).text_anchor_for_position(position, cx)
14908        else {
14909            return;
14910        };
14911
14912        let project = self.project.clone();
14913
14914        cx.spawn_in(window, async move |_, cx| {
14915            let result = find_file(&buffer, project, buffer_position, cx).await;
14916
14917            if let Some((_, path)) = result {
14918                workspace
14919                    .update_in(cx, |workspace, window, cx| {
14920                        workspace.open_resolved_path(path, window, cx)
14921                    })?
14922                    .await?;
14923            }
14924            anyhow::Ok(())
14925        })
14926        .detach();
14927    }
14928
14929    pub(crate) fn navigate_to_hover_links(
14930        &mut self,
14931        kind: Option<GotoDefinitionKind>,
14932        mut definitions: Vec<HoverLink>,
14933        split: bool,
14934        window: &mut Window,
14935        cx: &mut Context<Editor>,
14936    ) -> Task<Result<Navigated>> {
14937        // If there is one definition, just open it directly
14938        if definitions.len() == 1 {
14939            let definition = definitions.pop().unwrap();
14940
14941            enum TargetTaskResult {
14942                Location(Option<Location>),
14943                AlreadyNavigated,
14944            }
14945
14946            let target_task = match definition {
14947                HoverLink::Text(link) => {
14948                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14949                }
14950                HoverLink::InlayHint(lsp_location, server_id) => {
14951                    let computation =
14952                        self.compute_target_location(lsp_location, server_id, window, cx);
14953                    cx.background_spawn(async move {
14954                        let location = computation.await?;
14955                        Ok(TargetTaskResult::Location(location))
14956                    })
14957                }
14958                HoverLink::Url(url) => {
14959                    cx.open_url(&url);
14960                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14961                }
14962                HoverLink::File(path) => {
14963                    if let Some(workspace) = self.workspace() {
14964                        cx.spawn_in(window, async move |_, cx| {
14965                            workspace
14966                                .update_in(cx, |workspace, window, cx| {
14967                                    workspace.open_resolved_path(path, window, cx)
14968                                })?
14969                                .await
14970                                .map(|_| TargetTaskResult::AlreadyNavigated)
14971                        })
14972                    } else {
14973                        Task::ready(Ok(TargetTaskResult::Location(None)))
14974                    }
14975                }
14976            };
14977            cx.spawn_in(window, async move |editor, cx| {
14978                let target = match target_task.await.context("target resolution task")? {
14979                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14980                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14981                    TargetTaskResult::Location(Some(target)) => target,
14982                };
14983
14984                editor.update_in(cx, |editor, window, cx| {
14985                    let Some(workspace) = editor.workspace() else {
14986                        return Navigated::No;
14987                    };
14988                    let pane = workspace.read(cx).active_pane().clone();
14989
14990                    let range = target.range.to_point(target.buffer.read(cx));
14991                    let range = editor.range_for_match(&range);
14992                    let range = collapse_multiline_range(range);
14993
14994                    if !split
14995                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14996                    {
14997                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14998                    } else {
14999                        window.defer(cx, move |window, cx| {
15000                            let target_editor: Entity<Self> =
15001                                workspace.update(cx, |workspace, cx| {
15002                                    let pane = if split {
15003                                        workspace.adjacent_pane(window, cx)
15004                                    } else {
15005                                        workspace.active_pane().clone()
15006                                    };
15007
15008                                    workspace.open_project_item(
15009                                        pane,
15010                                        target.buffer.clone(),
15011                                        true,
15012                                        true,
15013                                        window,
15014                                        cx,
15015                                    )
15016                                });
15017                            target_editor.update(cx, |target_editor, cx| {
15018                                // When selecting a definition in a different buffer, disable the nav history
15019                                // to avoid creating a history entry at the previous cursor location.
15020                                pane.update(cx, |pane, _| pane.disable_history());
15021                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15022                                pane.update(cx, |pane, _| pane.enable_history());
15023                            });
15024                        });
15025                    }
15026                    Navigated::Yes
15027                })
15028            })
15029        } else if !definitions.is_empty() {
15030            cx.spawn_in(window, async move |editor, cx| {
15031                let (title, location_tasks, workspace) = editor
15032                    .update_in(cx, |editor, window, cx| {
15033                        let tab_kind = match kind {
15034                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15035                            _ => "Definitions",
15036                        };
15037                        let title = definitions
15038                            .iter()
15039                            .find_map(|definition| match definition {
15040                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15041                                    let buffer = origin.buffer.read(cx);
15042                                    format!(
15043                                        "{} for {}",
15044                                        tab_kind,
15045                                        buffer
15046                                            .text_for_range(origin.range.clone())
15047                                            .collect::<String>()
15048                                    )
15049                                }),
15050                                HoverLink::InlayHint(_, _) => None,
15051                                HoverLink::Url(_) => None,
15052                                HoverLink::File(_) => None,
15053                            })
15054                            .unwrap_or(tab_kind.to_string());
15055                        let location_tasks = definitions
15056                            .into_iter()
15057                            .map(|definition| match definition {
15058                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15059                                HoverLink::InlayHint(lsp_location, server_id) => editor
15060                                    .compute_target_location(lsp_location, server_id, window, cx),
15061                                HoverLink::Url(_) => Task::ready(Ok(None)),
15062                                HoverLink::File(_) => Task::ready(Ok(None)),
15063                            })
15064                            .collect::<Vec<_>>();
15065                        (title, location_tasks, editor.workspace().clone())
15066                    })
15067                    .context("location tasks preparation")?;
15068
15069                let locations = future::join_all(location_tasks)
15070                    .await
15071                    .into_iter()
15072                    .filter_map(|location| location.transpose())
15073                    .collect::<Result<_>>()
15074                    .context("location tasks")?;
15075
15076                let Some(workspace) = workspace else {
15077                    return Ok(Navigated::No);
15078                };
15079                let opened = workspace
15080                    .update_in(cx, |workspace, window, cx| {
15081                        Self::open_locations_in_multibuffer(
15082                            workspace,
15083                            locations,
15084                            title,
15085                            split,
15086                            MultibufferSelectionMode::First,
15087                            window,
15088                            cx,
15089                        )
15090                    })
15091                    .ok();
15092
15093                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15094            })
15095        } else {
15096            Task::ready(Ok(Navigated::No))
15097        }
15098    }
15099
15100    fn compute_target_location(
15101        &self,
15102        lsp_location: lsp::Location,
15103        server_id: LanguageServerId,
15104        window: &mut Window,
15105        cx: &mut Context<Self>,
15106    ) -> Task<anyhow::Result<Option<Location>>> {
15107        let Some(project) = self.project.clone() else {
15108            return Task::ready(Ok(None));
15109        };
15110
15111        cx.spawn_in(window, async move |editor, cx| {
15112            let location_task = editor.update(cx, |_, cx| {
15113                project.update(cx, |project, cx| {
15114                    let language_server_name = project
15115                        .language_server_statuses(cx)
15116                        .find(|(id, _)| server_id == *id)
15117                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15118                    language_server_name.map(|language_server_name| {
15119                        project.open_local_buffer_via_lsp(
15120                            lsp_location.uri.clone(),
15121                            server_id,
15122                            language_server_name,
15123                            cx,
15124                        )
15125                    })
15126                })
15127            })?;
15128            let location = match location_task {
15129                Some(task) => Some({
15130                    let target_buffer_handle = task.await.context("open local buffer")?;
15131                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15132                        let target_start = target_buffer
15133                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15134                        let target_end = target_buffer
15135                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15136                        target_buffer.anchor_after(target_start)
15137                            ..target_buffer.anchor_before(target_end)
15138                    })?;
15139                    Location {
15140                        buffer: target_buffer_handle,
15141                        range,
15142                    }
15143                }),
15144                None => None,
15145            };
15146            Ok(location)
15147        })
15148    }
15149
15150    pub fn find_all_references(
15151        &mut self,
15152        _: &FindAllReferences,
15153        window: &mut Window,
15154        cx: &mut Context<Self>,
15155    ) -> Option<Task<Result<Navigated>>> {
15156        let selection = self.selections.newest::<usize>(cx);
15157        let multi_buffer = self.buffer.read(cx);
15158        let head = selection.head();
15159
15160        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15161        let head_anchor = multi_buffer_snapshot.anchor_at(
15162            head,
15163            if head < selection.tail() {
15164                Bias::Right
15165            } else {
15166                Bias::Left
15167            },
15168        );
15169
15170        match self
15171            .find_all_references_task_sources
15172            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15173        {
15174            Ok(_) => {
15175                log::info!(
15176                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15177                );
15178                return None;
15179            }
15180            Err(i) => {
15181                self.find_all_references_task_sources.insert(i, head_anchor);
15182            }
15183        }
15184
15185        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15186        let workspace = self.workspace()?;
15187        let project = workspace.read(cx).project().clone();
15188        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15189        Some(cx.spawn_in(window, async move |editor, cx| {
15190            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15191                if let Ok(i) = editor
15192                    .find_all_references_task_sources
15193                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15194                {
15195                    editor.find_all_references_task_sources.remove(i);
15196                }
15197            });
15198
15199            let locations = references.await?;
15200            if locations.is_empty() {
15201                return anyhow::Ok(Navigated::No);
15202            }
15203
15204            workspace.update_in(cx, |workspace, window, cx| {
15205                let title = locations
15206                    .first()
15207                    .as_ref()
15208                    .map(|location| {
15209                        let buffer = location.buffer.read(cx);
15210                        format!(
15211                            "References to `{}`",
15212                            buffer
15213                                .text_for_range(location.range.clone())
15214                                .collect::<String>()
15215                        )
15216                    })
15217                    .unwrap();
15218                Self::open_locations_in_multibuffer(
15219                    workspace,
15220                    locations,
15221                    title,
15222                    false,
15223                    MultibufferSelectionMode::First,
15224                    window,
15225                    cx,
15226                );
15227                Navigated::Yes
15228            })
15229        }))
15230    }
15231
15232    /// Opens a multibuffer with the given project locations in it
15233    pub fn open_locations_in_multibuffer(
15234        workspace: &mut Workspace,
15235        mut locations: Vec<Location>,
15236        title: String,
15237        split: bool,
15238        multibuffer_selection_mode: MultibufferSelectionMode,
15239        window: &mut Window,
15240        cx: &mut Context<Workspace>,
15241    ) {
15242        // If there are multiple definitions, open them in a multibuffer
15243        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15244        let mut locations = locations.into_iter().peekable();
15245        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15246        let capability = workspace.project().read(cx).capability();
15247
15248        let excerpt_buffer = cx.new(|cx| {
15249            let mut multibuffer = MultiBuffer::new(capability);
15250            while let Some(location) = locations.next() {
15251                let buffer = location.buffer.read(cx);
15252                let mut ranges_for_buffer = Vec::new();
15253                let range = location.range.to_point(buffer);
15254                ranges_for_buffer.push(range.clone());
15255
15256                while let Some(next_location) = locations.peek() {
15257                    if next_location.buffer == location.buffer {
15258                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15259                        locations.next();
15260                    } else {
15261                        break;
15262                    }
15263                }
15264
15265                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15266                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15267                    PathKey::for_buffer(&location.buffer, cx),
15268                    location.buffer.clone(),
15269                    ranges_for_buffer,
15270                    DEFAULT_MULTIBUFFER_CONTEXT,
15271                    cx,
15272                );
15273                ranges.extend(new_ranges)
15274            }
15275
15276            multibuffer.with_title(title)
15277        });
15278
15279        let editor = cx.new(|cx| {
15280            Editor::for_multibuffer(
15281                excerpt_buffer,
15282                Some(workspace.project().clone()),
15283                window,
15284                cx,
15285            )
15286        });
15287        editor.update(cx, |editor, cx| {
15288            match multibuffer_selection_mode {
15289                MultibufferSelectionMode::First => {
15290                    if let Some(first_range) = ranges.first() {
15291                        editor.change_selections(None, window, cx, |selections| {
15292                            selections.clear_disjoint();
15293                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15294                        });
15295                    }
15296                    editor.highlight_background::<Self>(
15297                        &ranges,
15298                        |theme| theme.editor_highlighted_line_background,
15299                        cx,
15300                    );
15301                }
15302                MultibufferSelectionMode::All => {
15303                    editor.change_selections(None, window, cx, |selections| {
15304                        selections.clear_disjoint();
15305                        selections.select_anchor_ranges(ranges);
15306                    });
15307                }
15308            }
15309            editor.register_buffers_with_language_servers(cx);
15310        });
15311
15312        let item = Box::new(editor);
15313        let item_id = item.item_id();
15314
15315        if split {
15316            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15317        } else {
15318            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15319                let (preview_item_id, preview_item_idx) =
15320                    workspace.active_pane().read_with(cx, |pane, _| {
15321                        (pane.preview_item_id(), pane.preview_item_idx())
15322                    });
15323
15324                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15325
15326                if let Some(preview_item_id) = preview_item_id {
15327                    workspace.active_pane().update(cx, |pane, cx| {
15328                        pane.remove_item(preview_item_id, false, false, window, cx);
15329                    });
15330                }
15331            } else {
15332                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15333            }
15334        }
15335        workspace.active_pane().update(cx, |pane, cx| {
15336            pane.set_preview_item_id(Some(item_id), cx);
15337        });
15338    }
15339
15340    pub fn rename(
15341        &mut self,
15342        _: &Rename,
15343        window: &mut Window,
15344        cx: &mut Context<Self>,
15345    ) -> Option<Task<Result<()>>> {
15346        use language::ToOffset as _;
15347
15348        let provider = self.semantics_provider.clone()?;
15349        let selection = self.selections.newest_anchor().clone();
15350        let (cursor_buffer, cursor_buffer_position) = self
15351            .buffer
15352            .read(cx)
15353            .text_anchor_for_position(selection.head(), cx)?;
15354        let (tail_buffer, cursor_buffer_position_end) = self
15355            .buffer
15356            .read(cx)
15357            .text_anchor_for_position(selection.tail(), cx)?;
15358        if tail_buffer != cursor_buffer {
15359            return None;
15360        }
15361
15362        let snapshot = cursor_buffer.read(cx).snapshot();
15363        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15364        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15365        let prepare_rename = provider
15366            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15367            .unwrap_or_else(|| Task::ready(Ok(None)));
15368        drop(snapshot);
15369
15370        Some(cx.spawn_in(window, async move |this, cx| {
15371            let rename_range = if let Some(range) = prepare_rename.await? {
15372                Some(range)
15373            } else {
15374                this.update(cx, |this, cx| {
15375                    let buffer = this.buffer.read(cx).snapshot(cx);
15376                    let mut buffer_highlights = this
15377                        .document_highlights_for_position(selection.head(), &buffer)
15378                        .filter(|highlight| {
15379                            highlight.start.excerpt_id == selection.head().excerpt_id
15380                                && highlight.end.excerpt_id == selection.head().excerpt_id
15381                        });
15382                    buffer_highlights
15383                        .next()
15384                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15385                })?
15386            };
15387            if let Some(rename_range) = rename_range {
15388                this.update_in(cx, |this, window, cx| {
15389                    let snapshot = cursor_buffer.read(cx).snapshot();
15390                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15391                    let cursor_offset_in_rename_range =
15392                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15393                    let cursor_offset_in_rename_range_end =
15394                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15395
15396                    this.take_rename(false, window, cx);
15397                    let buffer = this.buffer.read(cx).read(cx);
15398                    let cursor_offset = selection.head().to_offset(&buffer);
15399                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15400                    let rename_end = rename_start + rename_buffer_range.len();
15401                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15402                    let mut old_highlight_id = None;
15403                    let old_name: Arc<str> = buffer
15404                        .chunks(rename_start..rename_end, true)
15405                        .map(|chunk| {
15406                            if old_highlight_id.is_none() {
15407                                old_highlight_id = chunk.syntax_highlight_id;
15408                            }
15409                            chunk.text
15410                        })
15411                        .collect::<String>()
15412                        .into();
15413
15414                    drop(buffer);
15415
15416                    // Position the selection in the rename editor so that it matches the current selection.
15417                    this.show_local_selections = false;
15418                    let rename_editor = cx.new(|cx| {
15419                        let mut editor = Editor::single_line(window, cx);
15420                        editor.buffer.update(cx, |buffer, cx| {
15421                            buffer.edit([(0..0, old_name.clone())], None, cx)
15422                        });
15423                        let rename_selection_range = match cursor_offset_in_rename_range
15424                            .cmp(&cursor_offset_in_rename_range_end)
15425                        {
15426                            Ordering::Equal => {
15427                                editor.select_all(&SelectAll, window, cx);
15428                                return editor;
15429                            }
15430                            Ordering::Less => {
15431                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15432                            }
15433                            Ordering::Greater => {
15434                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15435                            }
15436                        };
15437                        if rename_selection_range.end > old_name.len() {
15438                            editor.select_all(&SelectAll, window, cx);
15439                        } else {
15440                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15441                                s.select_ranges([rename_selection_range]);
15442                            });
15443                        }
15444                        editor
15445                    });
15446                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15447                        if e == &EditorEvent::Focused {
15448                            cx.emit(EditorEvent::FocusedIn)
15449                        }
15450                    })
15451                    .detach();
15452
15453                    let write_highlights =
15454                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15455                    let read_highlights =
15456                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15457                    let ranges = write_highlights
15458                        .iter()
15459                        .flat_map(|(_, ranges)| ranges.iter())
15460                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15461                        .cloned()
15462                        .collect();
15463
15464                    this.highlight_text::<Rename>(
15465                        ranges,
15466                        HighlightStyle {
15467                            fade_out: Some(0.6),
15468                            ..Default::default()
15469                        },
15470                        cx,
15471                    );
15472                    let rename_focus_handle = rename_editor.focus_handle(cx);
15473                    window.focus(&rename_focus_handle);
15474                    let block_id = this.insert_blocks(
15475                        [BlockProperties {
15476                            style: BlockStyle::Flex,
15477                            placement: BlockPlacement::Below(range.start),
15478                            height: Some(1),
15479                            render: Arc::new({
15480                                let rename_editor = rename_editor.clone();
15481                                move |cx: &mut BlockContext| {
15482                                    let mut text_style = cx.editor_style.text.clone();
15483                                    if let Some(highlight_style) = old_highlight_id
15484                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15485                                    {
15486                                        text_style = text_style.highlight(highlight_style);
15487                                    }
15488                                    div()
15489                                        .block_mouse_except_scroll()
15490                                        .pl(cx.anchor_x)
15491                                        .child(EditorElement::new(
15492                                            &rename_editor,
15493                                            EditorStyle {
15494                                                background: cx.theme().system().transparent,
15495                                                local_player: cx.editor_style.local_player,
15496                                                text: text_style,
15497                                                scrollbar_width: cx.editor_style.scrollbar_width,
15498                                                syntax: cx.editor_style.syntax.clone(),
15499                                                status: cx.editor_style.status.clone(),
15500                                                inlay_hints_style: HighlightStyle {
15501                                                    font_weight: Some(FontWeight::BOLD),
15502                                                    ..make_inlay_hints_style(cx.app)
15503                                                },
15504                                                inline_completion_styles: make_suggestion_styles(
15505                                                    cx.app,
15506                                                ),
15507                                                ..EditorStyle::default()
15508                                            },
15509                                        ))
15510                                        .into_any_element()
15511                                }
15512                            }),
15513                            priority: 0,
15514                            render_in_minimap: true,
15515                        }],
15516                        Some(Autoscroll::fit()),
15517                        cx,
15518                    )[0];
15519                    this.pending_rename = Some(RenameState {
15520                        range,
15521                        old_name,
15522                        editor: rename_editor,
15523                        block_id,
15524                    });
15525                })?;
15526            }
15527
15528            Ok(())
15529        }))
15530    }
15531
15532    pub fn confirm_rename(
15533        &mut self,
15534        _: &ConfirmRename,
15535        window: &mut Window,
15536        cx: &mut Context<Self>,
15537    ) -> Option<Task<Result<()>>> {
15538        let rename = self.take_rename(false, window, cx)?;
15539        let workspace = self.workspace()?.downgrade();
15540        let (buffer, start) = self
15541            .buffer
15542            .read(cx)
15543            .text_anchor_for_position(rename.range.start, cx)?;
15544        let (end_buffer, _) = self
15545            .buffer
15546            .read(cx)
15547            .text_anchor_for_position(rename.range.end, cx)?;
15548        if buffer != end_buffer {
15549            return None;
15550        }
15551
15552        let old_name = rename.old_name;
15553        let new_name = rename.editor.read(cx).text(cx);
15554
15555        let rename = self.semantics_provider.as_ref()?.perform_rename(
15556            &buffer,
15557            start,
15558            new_name.clone(),
15559            cx,
15560        )?;
15561
15562        Some(cx.spawn_in(window, async move |editor, cx| {
15563            let project_transaction = rename.await?;
15564            Self::open_project_transaction(
15565                &editor,
15566                workspace,
15567                project_transaction,
15568                format!("Rename: {}{}", old_name, new_name),
15569                cx,
15570            )
15571            .await?;
15572
15573            editor.update(cx, |editor, cx| {
15574                editor.refresh_document_highlights(cx);
15575            })?;
15576            Ok(())
15577        }))
15578    }
15579
15580    fn take_rename(
15581        &mut self,
15582        moving_cursor: bool,
15583        window: &mut Window,
15584        cx: &mut Context<Self>,
15585    ) -> Option<RenameState> {
15586        let rename = self.pending_rename.take()?;
15587        if rename.editor.focus_handle(cx).is_focused(window) {
15588            window.focus(&self.focus_handle);
15589        }
15590
15591        self.remove_blocks(
15592            [rename.block_id].into_iter().collect(),
15593            Some(Autoscroll::fit()),
15594            cx,
15595        );
15596        self.clear_highlights::<Rename>(cx);
15597        self.show_local_selections = true;
15598
15599        if moving_cursor {
15600            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15601                editor.selections.newest::<usize>(cx).head()
15602            });
15603
15604            // Update the selection to match the position of the selection inside
15605            // the rename editor.
15606            let snapshot = self.buffer.read(cx).read(cx);
15607            let rename_range = rename.range.to_offset(&snapshot);
15608            let cursor_in_editor = snapshot
15609                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15610                .min(rename_range.end);
15611            drop(snapshot);
15612
15613            self.change_selections(None, window, cx, |s| {
15614                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15615            });
15616        } else {
15617            self.refresh_document_highlights(cx);
15618        }
15619
15620        Some(rename)
15621    }
15622
15623    pub fn pending_rename(&self) -> Option<&RenameState> {
15624        self.pending_rename.as_ref()
15625    }
15626
15627    fn format(
15628        &mut self,
15629        _: &Format,
15630        window: &mut Window,
15631        cx: &mut Context<Self>,
15632    ) -> Option<Task<Result<()>>> {
15633        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15634
15635        let project = match &self.project {
15636            Some(project) => project.clone(),
15637            None => return None,
15638        };
15639
15640        Some(self.perform_format(
15641            project,
15642            FormatTrigger::Manual,
15643            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15644            window,
15645            cx,
15646        ))
15647    }
15648
15649    fn format_selections(
15650        &mut self,
15651        _: &FormatSelections,
15652        window: &mut Window,
15653        cx: &mut Context<Self>,
15654    ) -> Option<Task<Result<()>>> {
15655        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15656
15657        let project = match &self.project {
15658            Some(project) => project.clone(),
15659            None => return None,
15660        };
15661
15662        let ranges = self
15663            .selections
15664            .all_adjusted(cx)
15665            .into_iter()
15666            .map(|selection| selection.range())
15667            .collect_vec();
15668
15669        Some(self.perform_format(
15670            project,
15671            FormatTrigger::Manual,
15672            FormatTarget::Ranges(ranges),
15673            window,
15674            cx,
15675        ))
15676    }
15677
15678    fn perform_format(
15679        &mut self,
15680        project: Entity<Project>,
15681        trigger: FormatTrigger,
15682        target: FormatTarget,
15683        window: &mut Window,
15684        cx: &mut Context<Self>,
15685    ) -> Task<Result<()>> {
15686        let buffer = self.buffer.clone();
15687        let (buffers, target) = match target {
15688            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15689            FormatTarget::Ranges(selection_ranges) => {
15690                let multi_buffer = buffer.read(cx);
15691                let snapshot = multi_buffer.read(cx);
15692                let mut buffers = HashSet::default();
15693                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15694                    BTreeMap::new();
15695                for selection_range in selection_ranges {
15696                    for (buffer, buffer_range, _) in
15697                        snapshot.range_to_buffer_ranges(selection_range)
15698                    {
15699                        let buffer_id = buffer.remote_id();
15700                        let start = buffer.anchor_before(buffer_range.start);
15701                        let end = buffer.anchor_after(buffer_range.end);
15702                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15703                        buffer_id_to_ranges
15704                            .entry(buffer_id)
15705                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15706                            .or_insert_with(|| vec![start..end]);
15707                    }
15708                }
15709                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15710            }
15711        };
15712
15713        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15714        let selections_prev = transaction_id_prev
15715            .and_then(|transaction_id_prev| {
15716                // default to selections as they were after the last edit, if we have them,
15717                // instead of how they are now.
15718                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15719                // will take you back to where you made the last edit, instead of staying where you scrolled
15720                self.selection_history
15721                    .transaction(transaction_id_prev)
15722                    .map(|t| t.0.clone())
15723            })
15724            .unwrap_or_else(|| {
15725                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15726                self.selections.disjoint_anchors()
15727            });
15728
15729        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15730        let format = project.update(cx, |project, cx| {
15731            project.format(buffers, target, true, trigger, cx)
15732        });
15733
15734        cx.spawn_in(window, async move |editor, cx| {
15735            let transaction = futures::select_biased! {
15736                transaction = format.log_err().fuse() => transaction,
15737                () = timeout => {
15738                    log::warn!("timed out waiting for formatting");
15739                    None
15740                }
15741            };
15742
15743            buffer
15744                .update(cx, |buffer, cx| {
15745                    if let Some(transaction) = transaction {
15746                        if !buffer.is_singleton() {
15747                            buffer.push_transaction(&transaction.0, cx);
15748                        }
15749                    }
15750                    cx.notify();
15751                })
15752                .ok();
15753
15754            if let Some(transaction_id_now) =
15755                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15756            {
15757                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15758                if has_new_transaction {
15759                    _ = editor.update(cx, |editor, _| {
15760                        editor
15761                            .selection_history
15762                            .insert_transaction(transaction_id_now, selections_prev);
15763                    });
15764                }
15765            }
15766
15767            Ok(())
15768        })
15769    }
15770
15771    fn organize_imports(
15772        &mut self,
15773        _: &OrganizeImports,
15774        window: &mut Window,
15775        cx: &mut Context<Self>,
15776    ) -> Option<Task<Result<()>>> {
15777        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15778        let project = match &self.project {
15779            Some(project) => project.clone(),
15780            None => return None,
15781        };
15782        Some(self.perform_code_action_kind(
15783            project,
15784            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15785            window,
15786            cx,
15787        ))
15788    }
15789
15790    fn perform_code_action_kind(
15791        &mut self,
15792        project: Entity<Project>,
15793        kind: CodeActionKind,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) -> Task<Result<()>> {
15797        let buffer = self.buffer.clone();
15798        let buffers = buffer.read(cx).all_buffers();
15799        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15800        let apply_action = project.update(cx, |project, cx| {
15801            project.apply_code_action_kind(buffers, kind, true, cx)
15802        });
15803        cx.spawn_in(window, async move |_, cx| {
15804            let transaction = futures::select_biased! {
15805                () = timeout => {
15806                    log::warn!("timed out waiting for executing code action");
15807                    None
15808                }
15809                transaction = apply_action.log_err().fuse() => transaction,
15810            };
15811            buffer
15812                .update(cx, |buffer, cx| {
15813                    // check if we need this
15814                    if let Some(transaction) = transaction {
15815                        if !buffer.is_singleton() {
15816                            buffer.push_transaction(&transaction.0, cx);
15817                        }
15818                    }
15819                    cx.notify();
15820                })
15821                .ok();
15822            Ok(())
15823        })
15824    }
15825
15826    fn restart_language_server(
15827        &mut self,
15828        _: &RestartLanguageServer,
15829        _: &mut Window,
15830        cx: &mut Context<Self>,
15831    ) {
15832        if let Some(project) = self.project.clone() {
15833            self.buffer.update(cx, |multi_buffer, cx| {
15834                project.update(cx, |project, cx| {
15835                    project.restart_language_servers_for_buffers(
15836                        multi_buffer.all_buffers().into_iter().collect(),
15837                        cx,
15838                    );
15839                });
15840            })
15841        }
15842    }
15843
15844    fn stop_language_server(
15845        &mut self,
15846        _: &StopLanguageServer,
15847        _: &mut Window,
15848        cx: &mut Context<Self>,
15849    ) {
15850        if let Some(project) = self.project.clone() {
15851            self.buffer.update(cx, |multi_buffer, cx| {
15852                project.update(cx, |project, cx| {
15853                    project.stop_language_servers_for_buffers(
15854                        multi_buffer.all_buffers().into_iter().collect(),
15855                        cx,
15856                    );
15857                    cx.emit(project::Event::RefreshInlayHints);
15858                });
15859            });
15860        }
15861    }
15862
15863    fn cancel_language_server_work(
15864        workspace: &mut Workspace,
15865        _: &actions::CancelLanguageServerWork,
15866        _: &mut Window,
15867        cx: &mut Context<Workspace>,
15868    ) {
15869        let project = workspace.project();
15870        let buffers = workspace
15871            .active_item(cx)
15872            .and_then(|item| item.act_as::<Editor>(cx))
15873            .map_or(HashSet::default(), |editor| {
15874                editor.read(cx).buffer.read(cx).all_buffers()
15875            });
15876        project.update(cx, |project, cx| {
15877            project.cancel_language_server_work_for_buffers(buffers, cx);
15878        });
15879    }
15880
15881    fn show_character_palette(
15882        &mut self,
15883        _: &ShowCharacterPalette,
15884        window: &mut Window,
15885        _: &mut Context<Self>,
15886    ) {
15887        window.show_character_palette();
15888    }
15889
15890    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15891        if self.mode.is_minimap() {
15892            return;
15893        }
15894
15895        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15896            let buffer = self.buffer.read(cx).snapshot(cx);
15897            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15898            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15899            let is_valid = buffer
15900                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15901                .any(|entry| {
15902                    entry.diagnostic.is_primary
15903                        && !entry.range.is_empty()
15904                        && entry.range.start == primary_range_start
15905                        && entry.diagnostic.message == active_diagnostics.active_message
15906                });
15907
15908            if !is_valid {
15909                self.dismiss_diagnostics(cx);
15910            }
15911        }
15912    }
15913
15914    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15915        match &self.active_diagnostics {
15916            ActiveDiagnostic::Group(group) => Some(group),
15917            _ => None,
15918        }
15919    }
15920
15921    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15922        self.dismiss_diagnostics(cx);
15923        self.active_diagnostics = ActiveDiagnostic::All;
15924    }
15925
15926    fn activate_diagnostics(
15927        &mut self,
15928        buffer_id: BufferId,
15929        diagnostic: DiagnosticEntry<usize>,
15930        window: &mut Window,
15931        cx: &mut Context<Self>,
15932    ) {
15933        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15934            return;
15935        }
15936        self.dismiss_diagnostics(cx);
15937        let snapshot = self.snapshot(window, cx);
15938        let buffer = self.buffer.read(cx).snapshot(cx);
15939        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15940            return;
15941        };
15942
15943        let diagnostic_group = buffer
15944            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15945            .collect::<Vec<_>>();
15946
15947        let blocks =
15948            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15949
15950        let blocks = self.display_map.update(cx, |display_map, cx| {
15951            display_map.insert_blocks(blocks, cx).into_iter().collect()
15952        });
15953        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15954            active_range: buffer.anchor_before(diagnostic.range.start)
15955                ..buffer.anchor_after(diagnostic.range.end),
15956            active_message: diagnostic.diagnostic.message.clone(),
15957            group_id: diagnostic.diagnostic.group_id,
15958            blocks,
15959        });
15960        cx.notify();
15961    }
15962
15963    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15964        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15965            return;
15966        };
15967
15968        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15969        if let ActiveDiagnostic::Group(group) = prev {
15970            self.display_map.update(cx, |display_map, cx| {
15971                display_map.remove_blocks(group.blocks, cx);
15972            });
15973            cx.notify();
15974        }
15975    }
15976
15977    /// Disable inline diagnostics rendering for this editor.
15978    pub fn disable_inline_diagnostics(&mut self) {
15979        self.inline_diagnostics_enabled = false;
15980        self.inline_diagnostics_update = Task::ready(());
15981        self.inline_diagnostics.clear();
15982    }
15983
15984    pub fn diagnostics_enabled(&self) -> bool {
15985        self.mode.is_full()
15986    }
15987
15988    pub fn inline_diagnostics_enabled(&self) -> bool {
15989        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15990    }
15991
15992    pub fn show_inline_diagnostics(&self) -> bool {
15993        self.show_inline_diagnostics
15994    }
15995
15996    pub fn toggle_inline_diagnostics(
15997        &mut self,
15998        _: &ToggleInlineDiagnostics,
15999        window: &mut Window,
16000        cx: &mut Context<Editor>,
16001    ) {
16002        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16003        self.refresh_inline_diagnostics(false, window, cx);
16004    }
16005
16006    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16007        self.diagnostics_max_severity = severity;
16008        self.display_map.update(cx, |display_map, _| {
16009            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16010        });
16011    }
16012
16013    pub fn toggle_diagnostics(
16014        &mut self,
16015        _: &ToggleDiagnostics,
16016        window: &mut Window,
16017        cx: &mut Context<Editor>,
16018    ) {
16019        if !self.diagnostics_enabled() {
16020            return;
16021        }
16022
16023        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16024            EditorSettings::get_global(cx)
16025                .diagnostics_max_severity
16026                .filter(|severity| severity != &DiagnosticSeverity::Off)
16027                .unwrap_or(DiagnosticSeverity::Hint)
16028        } else {
16029            DiagnosticSeverity::Off
16030        };
16031        self.set_max_diagnostics_severity(new_severity, cx);
16032        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16033            self.active_diagnostics = ActiveDiagnostic::None;
16034            self.inline_diagnostics_update = Task::ready(());
16035            self.inline_diagnostics.clear();
16036        } else {
16037            self.refresh_inline_diagnostics(false, window, cx);
16038        }
16039
16040        cx.notify();
16041    }
16042
16043    pub fn toggle_minimap(
16044        &mut self,
16045        _: &ToggleMinimap,
16046        window: &mut Window,
16047        cx: &mut Context<Editor>,
16048    ) {
16049        if self.supports_minimap(cx) {
16050            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16051        }
16052    }
16053
16054    fn refresh_inline_diagnostics(
16055        &mut self,
16056        debounce: bool,
16057        window: &mut Window,
16058        cx: &mut Context<Self>,
16059    ) {
16060        let max_severity = ProjectSettings::get_global(cx)
16061            .diagnostics
16062            .inline
16063            .max_severity
16064            .unwrap_or(self.diagnostics_max_severity);
16065
16066        if !self.inline_diagnostics_enabled()
16067            || !self.show_inline_diagnostics
16068            || max_severity == DiagnosticSeverity::Off
16069        {
16070            self.inline_diagnostics_update = Task::ready(());
16071            self.inline_diagnostics.clear();
16072            return;
16073        }
16074
16075        let debounce_ms = ProjectSettings::get_global(cx)
16076            .diagnostics
16077            .inline
16078            .update_debounce_ms;
16079        let debounce = if debounce && debounce_ms > 0 {
16080            Some(Duration::from_millis(debounce_ms))
16081        } else {
16082            None
16083        };
16084        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16085            if let Some(debounce) = debounce {
16086                cx.background_executor().timer(debounce).await;
16087            }
16088            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16089                editor
16090                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16091                    .ok()
16092            }) else {
16093                return;
16094            };
16095
16096            let new_inline_diagnostics = cx
16097                .background_spawn(async move {
16098                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16099                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16100                        let message = diagnostic_entry
16101                            .diagnostic
16102                            .message
16103                            .split_once('\n')
16104                            .map(|(line, _)| line)
16105                            .map(SharedString::new)
16106                            .unwrap_or_else(|| {
16107                                SharedString::from(diagnostic_entry.diagnostic.message)
16108                            });
16109                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16110                        let (Ok(i) | Err(i)) = inline_diagnostics
16111                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16112                        inline_diagnostics.insert(
16113                            i,
16114                            (
16115                                start_anchor,
16116                                InlineDiagnostic {
16117                                    message,
16118                                    group_id: diagnostic_entry.diagnostic.group_id,
16119                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16120                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16121                                    severity: diagnostic_entry.diagnostic.severity,
16122                                },
16123                            ),
16124                        );
16125                    }
16126                    inline_diagnostics
16127                })
16128                .await;
16129
16130            editor
16131                .update(cx, |editor, cx| {
16132                    editor.inline_diagnostics = new_inline_diagnostics;
16133                    cx.notify();
16134                })
16135                .ok();
16136        });
16137    }
16138
16139    fn pull_diagnostics(
16140        &mut self,
16141        buffer_id: Option<BufferId>,
16142        window: &Window,
16143        cx: &mut Context<Self>,
16144    ) -> Option<()> {
16145        if !self.mode().is_full() {
16146            return None;
16147        }
16148        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16149            .diagnostics
16150            .lsp_pull_diagnostics;
16151        if !pull_diagnostics_settings.enabled {
16152            return None;
16153        }
16154        let project = self.project.as_ref()?.downgrade();
16155        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16156        let mut buffers = self.buffer.read(cx).all_buffers();
16157        if let Some(buffer_id) = buffer_id {
16158            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16159        }
16160
16161        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16162            cx.background_executor().timer(debounce).await;
16163
16164            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16165                buffers
16166                    .into_iter()
16167                    .flat_map(|buffer| {
16168                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16169                    })
16170                    .collect::<FuturesUnordered<_>>()
16171            }) else {
16172                return;
16173            };
16174
16175            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16176                match pull_task {
16177                    Ok(()) => {
16178                        if editor
16179                            .update_in(cx, |editor, window, cx| {
16180                                editor.update_diagnostics_state(window, cx);
16181                            })
16182                            .is_err()
16183                        {
16184                            return;
16185                        }
16186                    }
16187                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16188                }
16189            }
16190        });
16191
16192        Some(())
16193    }
16194
16195    pub fn set_selections_from_remote(
16196        &mut self,
16197        selections: Vec<Selection<Anchor>>,
16198        pending_selection: Option<Selection<Anchor>>,
16199        window: &mut Window,
16200        cx: &mut Context<Self>,
16201    ) {
16202        let old_cursor_position = self.selections.newest_anchor().head();
16203        self.selections.change_with(cx, |s| {
16204            s.select_anchors(selections);
16205            if let Some(pending_selection) = pending_selection {
16206                s.set_pending(pending_selection, SelectMode::Character);
16207            } else {
16208                s.clear_pending();
16209            }
16210        });
16211        self.selections_did_change(
16212            false,
16213            &old_cursor_position,
16214            SelectionEffects::default(),
16215            window,
16216            cx,
16217        );
16218    }
16219
16220    pub fn transact(
16221        &mut self,
16222        window: &mut Window,
16223        cx: &mut Context<Self>,
16224        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16225    ) -> Option<TransactionId> {
16226        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16227            this.start_transaction_at(Instant::now(), window, cx);
16228            update(this, window, cx);
16229            this.end_transaction_at(Instant::now(), cx)
16230        })
16231    }
16232
16233    pub fn start_transaction_at(
16234        &mut self,
16235        now: Instant,
16236        window: &mut Window,
16237        cx: &mut Context<Self>,
16238    ) {
16239        self.end_selection(window, cx);
16240        if let Some(tx_id) = self
16241            .buffer
16242            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16243        {
16244            self.selection_history
16245                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16246            cx.emit(EditorEvent::TransactionBegun {
16247                transaction_id: tx_id,
16248            })
16249        }
16250    }
16251
16252    pub fn end_transaction_at(
16253        &mut self,
16254        now: Instant,
16255        cx: &mut Context<Self>,
16256    ) -> Option<TransactionId> {
16257        if let Some(transaction_id) = self
16258            .buffer
16259            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16260        {
16261            if let Some((_, end_selections)) =
16262                self.selection_history.transaction_mut(transaction_id)
16263            {
16264                *end_selections = Some(self.selections.disjoint_anchors());
16265            } else {
16266                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16267            }
16268
16269            cx.emit(EditorEvent::Edited { transaction_id });
16270            Some(transaction_id)
16271        } else {
16272            None
16273        }
16274    }
16275
16276    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16277        if self.selection_mark_mode {
16278            self.change_selections(None, window, cx, |s| {
16279                s.move_with(|_, sel| {
16280                    sel.collapse_to(sel.head(), SelectionGoal::None);
16281                });
16282            })
16283        }
16284        self.selection_mark_mode = true;
16285        cx.notify();
16286    }
16287
16288    pub fn swap_selection_ends(
16289        &mut self,
16290        _: &actions::SwapSelectionEnds,
16291        window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) {
16294        self.change_selections(None, window, cx, |s| {
16295            s.move_with(|_, sel| {
16296                if sel.start != sel.end {
16297                    sel.reversed = !sel.reversed
16298                }
16299            });
16300        });
16301        self.request_autoscroll(Autoscroll::newest(), cx);
16302        cx.notify();
16303    }
16304
16305    pub fn toggle_fold(
16306        &mut self,
16307        _: &actions::ToggleFold,
16308        window: &mut Window,
16309        cx: &mut Context<Self>,
16310    ) {
16311        if self.is_singleton(cx) {
16312            let selection = self.selections.newest::<Point>(cx);
16313
16314            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16315            let range = if selection.is_empty() {
16316                let point = selection.head().to_display_point(&display_map);
16317                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16318                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16319                    .to_point(&display_map);
16320                start..end
16321            } else {
16322                selection.range()
16323            };
16324            if display_map.folds_in_range(range).next().is_some() {
16325                self.unfold_lines(&Default::default(), window, cx)
16326            } else {
16327                self.fold(&Default::default(), window, cx)
16328            }
16329        } else {
16330            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16331            let buffer_ids: HashSet<_> = self
16332                .selections
16333                .disjoint_anchor_ranges()
16334                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16335                .collect();
16336
16337            let should_unfold = buffer_ids
16338                .iter()
16339                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16340
16341            for buffer_id in buffer_ids {
16342                if should_unfold {
16343                    self.unfold_buffer(buffer_id, cx);
16344                } else {
16345                    self.fold_buffer(buffer_id, cx);
16346                }
16347            }
16348        }
16349    }
16350
16351    pub fn toggle_fold_recursive(
16352        &mut self,
16353        _: &actions::ToggleFoldRecursive,
16354        window: &mut Window,
16355        cx: &mut Context<Self>,
16356    ) {
16357        let selection = self.selections.newest::<Point>(cx);
16358
16359        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16360        let range = if selection.is_empty() {
16361            let point = selection.head().to_display_point(&display_map);
16362            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16363            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16364                .to_point(&display_map);
16365            start..end
16366        } else {
16367            selection.range()
16368        };
16369        if display_map.folds_in_range(range).next().is_some() {
16370            self.unfold_recursive(&Default::default(), window, cx)
16371        } else {
16372            self.fold_recursive(&Default::default(), window, cx)
16373        }
16374    }
16375
16376    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16377        if self.is_singleton(cx) {
16378            let mut to_fold = Vec::new();
16379            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16380            let selections = self.selections.all_adjusted(cx);
16381
16382            for selection in selections {
16383                let range = selection.range().sorted();
16384                let buffer_start_row = range.start.row;
16385
16386                if range.start.row != range.end.row {
16387                    let mut found = false;
16388                    let mut row = range.start.row;
16389                    while row <= range.end.row {
16390                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16391                        {
16392                            found = true;
16393                            row = crease.range().end.row + 1;
16394                            to_fold.push(crease);
16395                        } else {
16396                            row += 1
16397                        }
16398                    }
16399                    if found {
16400                        continue;
16401                    }
16402                }
16403
16404                for row in (0..=range.start.row).rev() {
16405                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16406                        if crease.range().end.row >= buffer_start_row {
16407                            to_fold.push(crease);
16408                            if row <= range.start.row {
16409                                break;
16410                            }
16411                        }
16412                    }
16413                }
16414            }
16415
16416            self.fold_creases(to_fold, true, window, cx);
16417        } else {
16418            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16419            let buffer_ids = self
16420                .selections
16421                .disjoint_anchor_ranges()
16422                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16423                .collect::<HashSet<_>>();
16424            for buffer_id in buffer_ids {
16425                self.fold_buffer(buffer_id, cx);
16426            }
16427        }
16428    }
16429
16430    fn fold_at_level(
16431        &mut self,
16432        fold_at: &FoldAtLevel,
16433        window: &mut Window,
16434        cx: &mut Context<Self>,
16435    ) {
16436        if !self.buffer.read(cx).is_singleton() {
16437            return;
16438        }
16439
16440        let fold_at_level = fold_at.0;
16441        let snapshot = self.buffer.read(cx).snapshot(cx);
16442        let mut to_fold = Vec::new();
16443        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16444
16445        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16446            while start_row < end_row {
16447                match self
16448                    .snapshot(window, cx)
16449                    .crease_for_buffer_row(MultiBufferRow(start_row))
16450                {
16451                    Some(crease) => {
16452                        let nested_start_row = crease.range().start.row + 1;
16453                        let nested_end_row = crease.range().end.row;
16454
16455                        if current_level < fold_at_level {
16456                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16457                        } else if current_level == fold_at_level {
16458                            to_fold.push(crease);
16459                        }
16460
16461                        start_row = nested_end_row + 1;
16462                    }
16463                    None => start_row += 1,
16464                }
16465            }
16466        }
16467
16468        self.fold_creases(to_fold, true, window, cx);
16469    }
16470
16471    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16472        if self.buffer.read(cx).is_singleton() {
16473            let mut fold_ranges = Vec::new();
16474            let snapshot = self.buffer.read(cx).snapshot(cx);
16475
16476            for row in 0..snapshot.max_row().0 {
16477                if let Some(foldable_range) = self
16478                    .snapshot(window, cx)
16479                    .crease_for_buffer_row(MultiBufferRow(row))
16480                {
16481                    fold_ranges.push(foldable_range);
16482                }
16483            }
16484
16485            self.fold_creases(fold_ranges, true, window, cx);
16486        } else {
16487            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16488                editor
16489                    .update_in(cx, |editor, _, cx| {
16490                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16491                            editor.fold_buffer(buffer_id, cx);
16492                        }
16493                    })
16494                    .ok();
16495            });
16496        }
16497    }
16498
16499    pub fn fold_function_bodies(
16500        &mut self,
16501        _: &actions::FoldFunctionBodies,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        let snapshot = self.buffer.read(cx).snapshot(cx);
16506
16507        let ranges = snapshot
16508            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16509            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16510            .collect::<Vec<_>>();
16511
16512        let creases = ranges
16513            .into_iter()
16514            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16515            .collect();
16516
16517        self.fold_creases(creases, true, window, cx);
16518    }
16519
16520    pub fn fold_recursive(
16521        &mut self,
16522        _: &actions::FoldRecursive,
16523        window: &mut Window,
16524        cx: &mut Context<Self>,
16525    ) {
16526        let mut to_fold = Vec::new();
16527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16528        let selections = self.selections.all_adjusted(cx);
16529
16530        for selection in selections {
16531            let range = selection.range().sorted();
16532            let buffer_start_row = range.start.row;
16533
16534            if range.start.row != range.end.row {
16535                let mut found = false;
16536                for row in range.start.row..=range.end.row {
16537                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16538                        found = true;
16539                        to_fold.push(crease);
16540                    }
16541                }
16542                if found {
16543                    continue;
16544                }
16545            }
16546
16547            for row in (0..=range.start.row).rev() {
16548                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16549                    if crease.range().end.row >= buffer_start_row {
16550                        to_fold.push(crease);
16551                    } else {
16552                        break;
16553                    }
16554                }
16555            }
16556        }
16557
16558        self.fold_creases(to_fold, true, window, cx);
16559    }
16560
16561    pub fn fold_at(
16562        &mut self,
16563        buffer_row: MultiBufferRow,
16564        window: &mut Window,
16565        cx: &mut Context<Self>,
16566    ) {
16567        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16568
16569        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16570            let autoscroll = self
16571                .selections
16572                .all::<Point>(cx)
16573                .iter()
16574                .any(|selection| crease.range().overlaps(&selection.range()));
16575
16576            self.fold_creases(vec![crease], autoscroll, window, cx);
16577        }
16578    }
16579
16580    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16581        if self.is_singleton(cx) {
16582            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16583            let buffer = &display_map.buffer_snapshot;
16584            let selections = self.selections.all::<Point>(cx);
16585            let ranges = selections
16586                .iter()
16587                .map(|s| {
16588                    let range = s.display_range(&display_map).sorted();
16589                    let mut start = range.start.to_point(&display_map);
16590                    let mut end = range.end.to_point(&display_map);
16591                    start.column = 0;
16592                    end.column = buffer.line_len(MultiBufferRow(end.row));
16593                    start..end
16594                })
16595                .collect::<Vec<_>>();
16596
16597            self.unfold_ranges(&ranges, true, true, cx);
16598        } else {
16599            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16600            let buffer_ids = self
16601                .selections
16602                .disjoint_anchor_ranges()
16603                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16604                .collect::<HashSet<_>>();
16605            for buffer_id in buffer_ids {
16606                self.unfold_buffer(buffer_id, cx);
16607            }
16608        }
16609    }
16610
16611    pub fn unfold_recursive(
16612        &mut self,
16613        _: &UnfoldRecursive,
16614        _window: &mut Window,
16615        cx: &mut Context<Self>,
16616    ) {
16617        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16618        let selections = self.selections.all::<Point>(cx);
16619        let ranges = selections
16620            .iter()
16621            .map(|s| {
16622                let mut range = s.display_range(&display_map).sorted();
16623                *range.start.column_mut() = 0;
16624                *range.end.column_mut() = display_map.line_len(range.end.row());
16625                let start = range.start.to_point(&display_map);
16626                let end = range.end.to_point(&display_map);
16627                start..end
16628            })
16629            .collect::<Vec<_>>();
16630
16631        self.unfold_ranges(&ranges, true, true, cx);
16632    }
16633
16634    pub fn unfold_at(
16635        &mut self,
16636        buffer_row: MultiBufferRow,
16637        _window: &mut Window,
16638        cx: &mut Context<Self>,
16639    ) {
16640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16641
16642        let intersection_range = Point::new(buffer_row.0, 0)
16643            ..Point::new(
16644                buffer_row.0,
16645                display_map.buffer_snapshot.line_len(buffer_row),
16646            );
16647
16648        let autoscroll = self
16649            .selections
16650            .all::<Point>(cx)
16651            .iter()
16652            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16653
16654        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16655    }
16656
16657    pub fn unfold_all(
16658        &mut self,
16659        _: &actions::UnfoldAll,
16660        _window: &mut Window,
16661        cx: &mut Context<Self>,
16662    ) {
16663        if self.buffer.read(cx).is_singleton() {
16664            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16665            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16666        } else {
16667            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16668                editor
16669                    .update(cx, |editor, cx| {
16670                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16671                            editor.unfold_buffer(buffer_id, cx);
16672                        }
16673                    })
16674                    .ok();
16675            });
16676        }
16677    }
16678
16679    pub fn fold_selected_ranges(
16680        &mut self,
16681        _: &FoldSelectedRanges,
16682        window: &mut Window,
16683        cx: &mut Context<Self>,
16684    ) {
16685        let selections = self.selections.all_adjusted(cx);
16686        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16687        let ranges = selections
16688            .into_iter()
16689            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16690            .collect::<Vec<_>>();
16691        self.fold_creases(ranges, true, window, cx);
16692    }
16693
16694    pub fn fold_ranges<T: ToOffset + Clone>(
16695        &mut self,
16696        ranges: Vec<Range<T>>,
16697        auto_scroll: bool,
16698        window: &mut Window,
16699        cx: &mut Context<Self>,
16700    ) {
16701        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16702        let ranges = ranges
16703            .into_iter()
16704            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16705            .collect::<Vec<_>>();
16706        self.fold_creases(ranges, auto_scroll, window, cx);
16707    }
16708
16709    pub fn fold_creases<T: ToOffset + Clone>(
16710        &mut self,
16711        creases: Vec<Crease<T>>,
16712        auto_scroll: bool,
16713        _window: &mut Window,
16714        cx: &mut Context<Self>,
16715    ) {
16716        if creases.is_empty() {
16717            return;
16718        }
16719
16720        let mut buffers_affected = HashSet::default();
16721        let multi_buffer = self.buffer().read(cx);
16722        for crease in &creases {
16723            if let Some((_, buffer, _)) =
16724                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16725            {
16726                buffers_affected.insert(buffer.read(cx).remote_id());
16727            };
16728        }
16729
16730        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16731
16732        if auto_scroll {
16733            self.request_autoscroll(Autoscroll::fit(), cx);
16734        }
16735
16736        cx.notify();
16737
16738        self.scrollbar_marker_state.dirty = true;
16739        self.folds_did_change(cx);
16740    }
16741
16742    /// Removes any folds whose ranges intersect any of the given ranges.
16743    pub fn unfold_ranges<T: ToOffset + Clone>(
16744        &mut self,
16745        ranges: &[Range<T>],
16746        inclusive: bool,
16747        auto_scroll: bool,
16748        cx: &mut Context<Self>,
16749    ) {
16750        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16751            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16752        });
16753        self.folds_did_change(cx);
16754    }
16755
16756    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16757        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16758            return;
16759        }
16760        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16761        self.display_map.update(cx, |display_map, cx| {
16762            display_map.fold_buffers([buffer_id], cx)
16763        });
16764        cx.emit(EditorEvent::BufferFoldToggled {
16765            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16766            folded: true,
16767        });
16768        cx.notify();
16769    }
16770
16771    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16772        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16773            return;
16774        }
16775        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16776        self.display_map.update(cx, |display_map, cx| {
16777            display_map.unfold_buffers([buffer_id], cx);
16778        });
16779        cx.emit(EditorEvent::BufferFoldToggled {
16780            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16781            folded: false,
16782        });
16783        cx.notify();
16784    }
16785
16786    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16787        self.display_map.read(cx).is_buffer_folded(buffer)
16788    }
16789
16790    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16791        self.display_map.read(cx).folded_buffers()
16792    }
16793
16794    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16795        self.display_map.update(cx, |display_map, cx| {
16796            display_map.disable_header_for_buffer(buffer_id, cx);
16797        });
16798        cx.notify();
16799    }
16800
16801    /// Removes any folds with the given ranges.
16802    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16803        &mut self,
16804        ranges: &[Range<T>],
16805        type_id: TypeId,
16806        auto_scroll: bool,
16807        cx: &mut Context<Self>,
16808    ) {
16809        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16810            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16811        });
16812        self.folds_did_change(cx);
16813    }
16814
16815    fn remove_folds_with<T: ToOffset + Clone>(
16816        &mut self,
16817        ranges: &[Range<T>],
16818        auto_scroll: bool,
16819        cx: &mut Context<Self>,
16820        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16821    ) {
16822        if ranges.is_empty() {
16823            return;
16824        }
16825
16826        let mut buffers_affected = HashSet::default();
16827        let multi_buffer = self.buffer().read(cx);
16828        for range in ranges {
16829            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16830                buffers_affected.insert(buffer.read(cx).remote_id());
16831            };
16832        }
16833
16834        self.display_map.update(cx, update);
16835
16836        if auto_scroll {
16837            self.request_autoscroll(Autoscroll::fit(), cx);
16838        }
16839
16840        cx.notify();
16841        self.scrollbar_marker_state.dirty = true;
16842        self.active_indent_guides_state.dirty = true;
16843    }
16844
16845    pub fn update_fold_widths(
16846        &mut self,
16847        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16848        cx: &mut Context<Self>,
16849    ) -> bool {
16850        self.display_map
16851            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16852    }
16853
16854    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16855        self.display_map.read(cx).fold_placeholder.clone()
16856    }
16857
16858    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16859        self.buffer.update(cx, |buffer, cx| {
16860            buffer.set_all_diff_hunks_expanded(cx);
16861        });
16862    }
16863
16864    pub fn expand_all_diff_hunks(
16865        &mut self,
16866        _: &ExpandAllDiffHunks,
16867        _window: &mut Window,
16868        cx: &mut Context<Self>,
16869    ) {
16870        self.buffer.update(cx, |buffer, cx| {
16871            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16872        });
16873    }
16874
16875    pub fn toggle_selected_diff_hunks(
16876        &mut self,
16877        _: &ToggleSelectedDiffHunks,
16878        _window: &mut Window,
16879        cx: &mut Context<Self>,
16880    ) {
16881        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16882        self.toggle_diff_hunks_in_ranges(ranges, cx);
16883    }
16884
16885    pub fn diff_hunks_in_ranges<'a>(
16886        &'a self,
16887        ranges: &'a [Range<Anchor>],
16888        buffer: &'a MultiBufferSnapshot,
16889    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16890        ranges.iter().flat_map(move |range| {
16891            let end_excerpt_id = range.end.excerpt_id;
16892            let range = range.to_point(buffer);
16893            let mut peek_end = range.end;
16894            if range.end.row < buffer.max_row().0 {
16895                peek_end = Point::new(range.end.row + 1, 0);
16896            }
16897            buffer
16898                .diff_hunks_in_range(range.start..peek_end)
16899                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16900        })
16901    }
16902
16903    pub fn has_stageable_diff_hunks_in_ranges(
16904        &self,
16905        ranges: &[Range<Anchor>],
16906        snapshot: &MultiBufferSnapshot,
16907    ) -> bool {
16908        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16909        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16910    }
16911
16912    pub fn toggle_staged_selected_diff_hunks(
16913        &mut self,
16914        _: &::git::ToggleStaged,
16915        _: &mut Window,
16916        cx: &mut Context<Self>,
16917    ) {
16918        let snapshot = self.buffer.read(cx).snapshot(cx);
16919        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16920        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16921        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16922    }
16923
16924    pub fn set_render_diff_hunk_controls(
16925        &mut self,
16926        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16927        cx: &mut Context<Self>,
16928    ) {
16929        self.render_diff_hunk_controls = render_diff_hunk_controls;
16930        cx.notify();
16931    }
16932
16933    pub fn stage_and_next(
16934        &mut self,
16935        _: &::git::StageAndNext,
16936        window: &mut Window,
16937        cx: &mut Context<Self>,
16938    ) {
16939        self.do_stage_or_unstage_and_next(true, window, cx);
16940    }
16941
16942    pub fn unstage_and_next(
16943        &mut self,
16944        _: &::git::UnstageAndNext,
16945        window: &mut Window,
16946        cx: &mut Context<Self>,
16947    ) {
16948        self.do_stage_or_unstage_and_next(false, window, cx);
16949    }
16950
16951    pub fn stage_or_unstage_diff_hunks(
16952        &mut self,
16953        stage: bool,
16954        ranges: Vec<Range<Anchor>>,
16955        cx: &mut Context<Self>,
16956    ) {
16957        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16958        cx.spawn(async move |this, cx| {
16959            task.await?;
16960            this.update(cx, |this, cx| {
16961                let snapshot = this.buffer.read(cx).snapshot(cx);
16962                let chunk_by = this
16963                    .diff_hunks_in_ranges(&ranges, &snapshot)
16964                    .chunk_by(|hunk| hunk.buffer_id);
16965                for (buffer_id, hunks) in &chunk_by {
16966                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16967                }
16968            })
16969        })
16970        .detach_and_log_err(cx);
16971    }
16972
16973    fn save_buffers_for_ranges_if_needed(
16974        &mut self,
16975        ranges: &[Range<Anchor>],
16976        cx: &mut Context<Editor>,
16977    ) -> Task<Result<()>> {
16978        let multibuffer = self.buffer.read(cx);
16979        let snapshot = multibuffer.read(cx);
16980        let buffer_ids: HashSet<_> = ranges
16981            .iter()
16982            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16983            .collect();
16984        drop(snapshot);
16985
16986        let mut buffers = HashSet::default();
16987        for buffer_id in buffer_ids {
16988            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16989                let buffer = buffer_entity.read(cx);
16990                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16991                {
16992                    buffers.insert(buffer_entity);
16993                }
16994            }
16995        }
16996
16997        if let Some(project) = &self.project {
16998            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16999        } else {
17000            Task::ready(Ok(()))
17001        }
17002    }
17003
17004    fn do_stage_or_unstage_and_next(
17005        &mut self,
17006        stage: bool,
17007        window: &mut Window,
17008        cx: &mut Context<Self>,
17009    ) {
17010        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17011
17012        if ranges.iter().any(|range| range.start != range.end) {
17013            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17014            return;
17015        }
17016
17017        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17018        let snapshot = self.snapshot(window, cx);
17019        let position = self.selections.newest::<Point>(cx).head();
17020        let mut row = snapshot
17021            .buffer_snapshot
17022            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17023            .find(|hunk| hunk.row_range.start.0 > position.row)
17024            .map(|hunk| hunk.row_range.start);
17025
17026        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17027        // Outside of the project diff editor, wrap around to the beginning.
17028        if !all_diff_hunks_expanded {
17029            row = row.or_else(|| {
17030                snapshot
17031                    .buffer_snapshot
17032                    .diff_hunks_in_range(Point::zero()..position)
17033                    .find(|hunk| hunk.row_range.end.0 < position.row)
17034                    .map(|hunk| hunk.row_range.start)
17035            });
17036        }
17037
17038        if let Some(row) = row {
17039            let destination = Point::new(row.0, 0);
17040            let autoscroll = Autoscroll::center();
17041
17042            self.unfold_ranges(&[destination..destination], false, false, cx);
17043            self.change_selections(Some(autoscroll), window, cx, |s| {
17044                s.select_ranges([destination..destination]);
17045            });
17046        }
17047    }
17048
17049    fn do_stage_or_unstage(
17050        &self,
17051        stage: bool,
17052        buffer_id: BufferId,
17053        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17054        cx: &mut App,
17055    ) -> Option<()> {
17056        let project = self.project.as_ref()?;
17057        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17058        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17059        let buffer_snapshot = buffer.read(cx).snapshot();
17060        let file_exists = buffer_snapshot
17061            .file()
17062            .is_some_and(|file| file.disk_state().exists());
17063        diff.update(cx, |diff, cx| {
17064            diff.stage_or_unstage_hunks(
17065                stage,
17066                &hunks
17067                    .map(|hunk| buffer_diff::DiffHunk {
17068                        buffer_range: hunk.buffer_range,
17069                        diff_base_byte_range: hunk.diff_base_byte_range,
17070                        secondary_status: hunk.secondary_status,
17071                        range: Point::zero()..Point::zero(), // unused
17072                    })
17073                    .collect::<Vec<_>>(),
17074                &buffer_snapshot,
17075                file_exists,
17076                cx,
17077            )
17078        });
17079        None
17080    }
17081
17082    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17083        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17084        self.buffer
17085            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17086    }
17087
17088    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17089        self.buffer.update(cx, |buffer, cx| {
17090            let ranges = vec![Anchor::min()..Anchor::max()];
17091            if !buffer.all_diff_hunks_expanded()
17092                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17093            {
17094                buffer.collapse_diff_hunks(ranges, cx);
17095                true
17096            } else {
17097                false
17098            }
17099        })
17100    }
17101
17102    fn toggle_diff_hunks_in_ranges(
17103        &mut self,
17104        ranges: Vec<Range<Anchor>>,
17105        cx: &mut Context<Editor>,
17106    ) {
17107        self.buffer.update(cx, |buffer, cx| {
17108            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17109            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17110        })
17111    }
17112
17113    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17114        self.buffer.update(cx, |buffer, cx| {
17115            let snapshot = buffer.snapshot(cx);
17116            let excerpt_id = range.end.excerpt_id;
17117            let point_range = range.to_point(&snapshot);
17118            let expand = !buffer.single_hunk_is_expanded(range, cx);
17119            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17120        })
17121    }
17122
17123    pub(crate) fn apply_all_diff_hunks(
17124        &mut self,
17125        _: &ApplyAllDiffHunks,
17126        window: &mut Window,
17127        cx: &mut Context<Self>,
17128    ) {
17129        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17130
17131        let buffers = self.buffer.read(cx).all_buffers();
17132        for branch_buffer in buffers {
17133            branch_buffer.update(cx, |branch_buffer, cx| {
17134                branch_buffer.merge_into_base(Vec::new(), cx);
17135            });
17136        }
17137
17138        if let Some(project) = self.project.clone() {
17139            self.save(
17140                SaveOptions {
17141                    format: true,
17142                    autosave: false,
17143                },
17144                project,
17145                window,
17146                cx,
17147            )
17148            .detach_and_log_err(cx);
17149        }
17150    }
17151
17152    pub(crate) fn apply_selected_diff_hunks(
17153        &mut self,
17154        _: &ApplyDiffHunk,
17155        window: &mut Window,
17156        cx: &mut Context<Self>,
17157    ) {
17158        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17159        let snapshot = self.snapshot(window, cx);
17160        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17161        let mut ranges_by_buffer = HashMap::default();
17162        self.transact(window, cx, |editor, _window, cx| {
17163            for hunk in hunks {
17164                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17165                    ranges_by_buffer
17166                        .entry(buffer.clone())
17167                        .or_insert_with(Vec::new)
17168                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17169                }
17170            }
17171
17172            for (buffer, ranges) in ranges_by_buffer {
17173                buffer.update(cx, |buffer, cx| {
17174                    buffer.merge_into_base(ranges, cx);
17175                });
17176            }
17177        });
17178
17179        if let Some(project) = self.project.clone() {
17180            self.save(
17181                SaveOptions {
17182                    format: true,
17183                    autosave: false,
17184                },
17185                project,
17186                window,
17187                cx,
17188            )
17189            .detach_and_log_err(cx);
17190        }
17191    }
17192
17193    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17194        if hovered != self.gutter_hovered {
17195            self.gutter_hovered = hovered;
17196            cx.notify();
17197        }
17198    }
17199
17200    pub fn insert_blocks(
17201        &mut self,
17202        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17203        autoscroll: Option<Autoscroll>,
17204        cx: &mut Context<Self>,
17205    ) -> Vec<CustomBlockId> {
17206        let blocks = self
17207            .display_map
17208            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17209        if let Some(autoscroll) = autoscroll {
17210            self.request_autoscroll(autoscroll, cx);
17211        }
17212        cx.notify();
17213        blocks
17214    }
17215
17216    pub fn resize_blocks(
17217        &mut self,
17218        heights: HashMap<CustomBlockId, u32>,
17219        autoscroll: Option<Autoscroll>,
17220        cx: &mut Context<Self>,
17221    ) {
17222        self.display_map
17223            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17224        if let Some(autoscroll) = autoscroll {
17225            self.request_autoscroll(autoscroll, cx);
17226        }
17227        cx.notify();
17228    }
17229
17230    pub fn replace_blocks(
17231        &mut self,
17232        renderers: HashMap<CustomBlockId, RenderBlock>,
17233        autoscroll: Option<Autoscroll>,
17234        cx: &mut Context<Self>,
17235    ) {
17236        self.display_map
17237            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17238        if let Some(autoscroll) = autoscroll {
17239            self.request_autoscroll(autoscroll, cx);
17240        }
17241        cx.notify();
17242    }
17243
17244    pub fn remove_blocks(
17245        &mut self,
17246        block_ids: HashSet<CustomBlockId>,
17247        autoscroll: Option<Autoscroll>,
17248        cx: &mut Context<Self>,
17249    ) {
17250        self.display_map.update(cx, |display_map, cx| {
17251            display_map.remove_blocks(block_ids, cx)
17252        });
17253        if let Some(autoscroll) = autoscroll {
17254            self.request_autoscroll(autoscroll, cx);
17255        }
17256        cx.notify();
17257    }
17258
17259    pub fn row_for_block(
17260        &self,
17261        block_id: CustomBlockId,
17262        cx: &mut Context<Self>,
17263    ) -> Option<DisplayRow> {
17264        self.display_map
17265            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17266    }
17267
17268    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17269        self.focused_block = Some(focused_block);
17270    }
17271
17272    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17273        self.focused_block.take()
17274    }
17275
17276    pub fn insert_creases(
17277        &mut self,
17278        creases: impl IntoIterator<Item = Crease<Anchor>>,
17279        cx: &mut Context<Self>,
17280    ) -> Vec<CreaseId> {
17281        self.display_map
17282            .update(cx, |map, cx| map.insert_creases(creases, cx))
17283    }
17284
17285    pub fn remove_creases(
17286        &mut self,
17287        ids: impl IntoIterator<Item = CreaseId>,
17288        cx: &mut Context<Self>,
17289    ) -> Vec<(CreaseId, Range<Anchor>)> {
17290        self.display_map
17291            .update(cx, |map, cx| map.remove_creases(ids, cx))
17292    }
17293
17294    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17295        self.display_map
17296            .update(cx, |map, cx| map.snapshot(cx))
17297            .longest_row()
17298    }
17299
17300    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17301        self.display_map
17302            .update(cx, |map, cx| map.snapshot(cx))
17303            .max_point()
17304    }
17305
17306    pub fn text(&self, cx: &App) -> String {
17307        self.buffer.read(cx).read(cx).text()
17308    }
17309
17310    pub fn is_empty(&self, cx: &App) -> bool {
17311        self.buffer.read(cx).read(cx).is_empty()
17312    }
17313
17314    pub fn text_option(&self, cx: &App) -> Option<String> {
17315        let text = self.text(cx);
17316        let text = text.trim();
17317
17318        if text.is_empty() {
17319            return None;
17320        }
17321
17322        Some(text.to_string())
17323    }
17324
17325    pub fn set_text(
17326        &mut self,
17327        text: impl Into<Arc<str>>,
17328        window: &mut Window,
17329        cx: &mut Context<Self>,
17330    ) {
17331        self.transact(window, cx, |this, _, cx| {
17332            this.buffer
17333                .read(cx)
17334                .as_singleton()
17335                .expect("you can only call set_text on editors for singleton buffers")
17336                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17337        });
17338    }
17339
17340    pub fn display_text(&self, cx: &mut App) -> String {
17341        self.display_map
17342            .update(cx, |map, cx| map.snapshot(cx))
17343            .text()
17344    }
17345
17346    fn create_minimap(
17347        &self,
17348        minimap_settings: MinimapSettings,
17349        window: &mut Window,
17350        cx: &mut Context<Self>,
17351    ) -> Option<Entity<Self>> {
17352        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17353            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17354    }
17355
17356    fn initialize_new_minimap(
17357        &self,
17358        minimap_settings: MinimapSettings,
17359        window: &mut Window,
17360        cx: &mut Context<Self>,
17361    ) -> Entity<Self> {
17362        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17363
17364        let mut minimap = Editor::new_internal(
17365            EditorMode::Minimap {
17366                parent: cx.weak_entity(),
17367            },
17368            self.buffer.clone(),
17369            self.project.clone(),
17370            Some(self.display_map.clone()),
17371            window,
17372            cx,
17373        );
17374        minimap.scroll_manager.clone_state(&self.scroll_manager);
17375        minimap.set_text_style_refinement(TextStyleRefinement {
17376            font_size: Some(MINIMAP_FONT_SIZE),
17377            font_weight: Some(MINIMAP_FONT_WEIGHT),
17378            ..Default::default()
17379        });
17380        minimap.update_minimap_configuration(minimap_settings, cx);
17381        cx.new(|_| minimap)
17382    }
17383
17384    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17385        let current_line_highlight = minimap_settings
17386            .current_line_highlight
17387            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17388        self.set_current_line_highlight(Some(current_line_highlight));
17389    }
17390
17391    pub fn minimap(&self) -> Option<&Entity<Self>> {
17392        self.minimap
17393            .as_ref()
17394            .filter(|_| self.minimap_visibility.visible())
17395    }
17396
17397    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17398        let mut wrap_guides = smallvec![];
17399
17400        if self.show_wrap_guides == Some(false) {
17401            return wrap_guides;
17402        }
17403
17404        let settings = self.buffer.read(cx).language_settings(cx);
17405        if settings.show_wrap_guides {
17406            match self.soft_wrap_mode(cx) {
17407                SoftWrap::Column(soft_wrap) => {
17408                    wrap_guides.push((soft_wrap as usize, true));
17409                }
17410                SoftWrap::Bounded(soft_wrap) => {
17411                    wrap_guides.push((soft_wrap as usize, true));
17412                }
17413                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17414            }
17415            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17416        }
17417
17418        wrap_guides
17419    }
17420
17421    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17422        let settings = self.buffer.read(cx).language_settings(cx);
17423        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17424        match mode {
17425            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17426                SoftWrap::None
17427            }
17428            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17429            language_settings::SoftWrap::PreferredLineLength => {
17430                SoftWrap::Column(settings.preferred_line_length)
17431            }
17432            language_settings::SoftWrap::Bounded => {
17433                SoftWrap::Bounded(settings.preferred_line_length)
17434            }
17435        }
17436    }
17437
17438    pub fn set_soft_wrap_mode(
17439        &mut self,
17440        mode: language_settings::SoftWrap,
17441
17442        cx: &mut Context<Self>,
17443    ) {
17444        self.soft_wrap_mode_override = Some(mode);
17445        cx.notify();
17446    }
17447
17448    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17449        self.hard_wrap = hard_wrap;
17450        cx.notify();
17451    }
17452
17453    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17454        self.text_style_refinement = Some(style);
17455    }
17456
17457    /// called by the Element so we know what style we were most recently rendered with.
17458    pub(crate) fn set_style(
17459        &mut self,
17460        style: EditorStyle,
17461        window: &mut Window,
17462        cx: &mut Context<Self>,
17463    ) {
17464        // We intentionally do not inform the display map about the minimap style
17465        // so that wrapping is not recalculated and stays consistent for the editor
17466        // and its linked minimap.
17467        if !self.mode.is_minimap() {
17468            let rem_size = window.rem_size();
17469            self.display_map.update(cx, |map, cx| {
17470                map.set_font(
17471                    style.text.font(),
17472                    style.text.font_size.to_pixels(rem_size),
17473                    cx,
17474                )
17475            });
17476        }
17477        self.style = Some(style);
17478    }
17479
17480    pub fn style(&self) -> Option<&EditorStyle> {
17481        self.style.as_ref()
17482    }
17483
17484    // Called by the element. This method is not designed to be called outside of the editor
17485    // element's layout code because it does not notify when rewrapping is computed synchronously.
17486    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17487        self.display_map
17488            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17489    }
17490
17491    pub fn set_soft_wrap(&mut self) {
17492        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17493    }
17494
17495    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17496        if self.soft_wrap_mode_override.is_some() {
17497            self.soft_wrap_mode_override.take();
17498        } else {
17499            let soft_wrap = match self.soft_wrap_mode(cx) {
17500                SoftWrap::GitDiff => return,
17501                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17502                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17503                    language_settings::SoftWrap::None
17504                }
17505            };
17506            self.soft_wrap_mode_override = Some(soft_wrap);
17507        }
17508        cx.notify();
17509    }
17510
17511    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17512        let Some(workspace) = self.workspace() else {
17513            return;
17514        };
17515        let fs = workspace.read(cx).app_state().fs.clone();
17516        let current_show = TabBarSettings::get_global(cx).show;
17517        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17518            setting.show = Some(!current_show);
17519        });
17520    }
17521
17522    pub fn toggle_indent_guides(
17523        &mut self,
17524        _: &ToggleIndentGuides,
17525        _: &mut Window,
17526        cx: &mut Context<Self>,
17527    ) {
17528        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17529            self.buffer
17530                .read(cx)
17531                .language_settings(cx)
17532                .indent_guides
17533                .enabled
17534        });
17535        self.show_indent_guides = Some(!currently_enabled);
17536        cx.notify();
17537    }
17538
17539    fn should_show_indent_guides(&self) -> Option<bool> {
17540        self.show_indent_guides
17541    }
17542
17543    pub fn toggle_line_numbers(
17544        &mut self,
17545        _: &ToggleLineNumbers,
17546        _: &mut Window,
17547        cx: &mut Context<Self>,
17548    ) {
17549        let mut editor_settings = EditorSettings::get_global(cx).clone();
17550        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17551        EditorSettings::override_global(editor_settings, cx);
17552    }
17553
17554    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17555        if let Some(show_line_numbers) = self.show_line_numbers {
17556            return show_line_numbers;
17557        }
17558        EditorSettings::get_global(cx).gutter.line_numbers
17559    }
17560
17561    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17562        self.use_relative_line_numbers
17563            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17564    }
17565
17566    pub fn toggle_relative_line_numbers(
17567        &mut self,
17568        _: &ToggleRelativeLineNumbers,
17569        _: &mut Window,
17570        cx: &mut Context<Self>,
17571    ) {
17572        let is_relative = self.should_use_relative_line_numbers(cx);
17573        self.set_relative_line_number(Some(!is_relative), cx)
17574    }
17575
17576    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17577        self.use_relative_line_numbers = is_relative;
17578        cx.notify();
17579    }
17580
17581    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17582        self.show_gutter = show_gutter;
17583        cx.notify();
17584    }
17585
17586    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17587        self.show_scrollbars = ScrollbarAxes {
17588            horizontal: show,
17589            vertical: show,
17590        };
17591        cx.notify();
17592    }
17593
17594    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17595        self.show_scrollbars.vertical = show;
17596        cx.notify();
17597    }
17598
17599    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17600        self.show_scrollbars.horizontal = show;
17601        cx.notify();
17602    }
17603
17604    pub fn set_minimap_visibility(
17605        &mut self,
17606        minimap_visibility: MinimapVisibility,
17607        window: &mut Window,
17608        cx: &mut Context<Self>,
17609    ) {
17610        if self.minimap_visibility != minimap_visibility {
17611            if minimap_visibility.visible() && self.minimap.is_none() {
17612                let minimap_settings = EditorSettings::get_global(cx).minimap;
17613                self.minimap =
17614                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17615            }
17616            self.minimap_visibility = minimap_visibility;
17617            cx.notify();
17618        }
17619    }
17620
17621    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17622        self.set_show_scrollbars(false, cx);
17623        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17624    }
17625
17626    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17627        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17628    }
17629
17630    /// Normally the text in full mode and auto height editors is padded on the
17631    /// left side by roughly half a character width for improved hit testing.
17632    ///
17633    /// Use this method to disable this for cases where this is not wanted (e.g.
17634    /// if you want to align the editor text with some other text above or below)
17635    /// or if you want to add this padding to single-line editors.
17636    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17637        self.offset_content = offset_content;
17638        cx.notify();
17639    }
17640
17641    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17642        self.show_line_numbers = Some(show_line_numbers);
17643        cx.notify();
17644    }
17645
17646    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17647        self.disable_expand_excerpt_buttons = true;
17648        cx.notify();
17649    }
17650
17651    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17652        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17653        cx.notify();
17654    }
17655
17656    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17657        self.show_code_actions = Some(show_code_actions);
17658        cx.notify();
17659    }
17660
17661    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17662        self.show_runnables = Some(show_runnables);
17663        cx.notify();
17664    }
17665
17666    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17667        self.show_breakpoints = Some(show_breakpoints);
17668        cx.notify();
17669    }
17670
17671    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17672        if self.display_map.read(cx).masked != masked {
17673            self.display_map.update(cx, |map, _| map.masked = masked);
17674        }
17675        cx.notify()
17676    }
17677
17678    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17679        self.show_wrap_guides = Some(show_wrap_guides);
17680        cx.notify();
17681    }
17682
17683    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17684        self.show_indent_guides = Some(show_indent_guides);
17685        cx.notify();
17686    }
17687
17688    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17689        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17690            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17691                if let Some(dir) = file.abs_path(cx).parent() {
17692                    return Some(dir.to_owned());
17693                }
17694            }
17695
17696            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17697                return Some(project_path.path.to_path_buf());
17698            }
17699        }
17700
17701        None
17702    }
17703
17704    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17705        self.active_excerpt(cx)?
17706            .1
17707            .read(cx)
17708            .file()
17709            .and_then(|f| f.as_local())
17710    }
17711
17712    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17713        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17714            let buffer = buffer.read(cx);
17715            if let Some(project_path) = buffer.project_path(cx) {
17716                let project = self.project.as_ref()?.read(cx);
17717                project.absolute_path(&project_path, cx)
17718            } else {
17719                buffer
17720                    .file()
17721                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17722            }
17723        })
17724    }
17725
17726    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17727        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17728            let project_path = buffer.read(cx).project_path(cx)?;
17729            let project = self.project.as_ref()?.read(cx);
17730            let entry = project.entry_for_path(&project_path, cx)?;
17731            let path = entry.path.to_path_buf();
17732            Some(path)
17733        })
17734    }
17735
17736    pub fn reveal_in_finder(
17737        &mut self,
17738        _: &RevealInFileManager,
17739        _window: &mut Window,
17740        cx: &mut Context<Self>,
17741    ) {
17742        if let Some(target) = self.target_file(cx) {
17743            cx.reveal_path(&target.abs_path(cx));
17744        }
17745    }
17746
17747    pub fn copy_path(
17748        &mut self,
17749        _: &zed_actions::workspace::CopyPath,
17750        _window: &mut Window,
17751        cx: &mut Context<Self>,
17752    ) {
17753        if let Some(path) = self.target_file_abs_path(cx) {
17754            if let Some(path) = path.to_str() {
17755                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17756            }
17757        }
17758    }
17759
17760    pub fn copy_relative_path(
17761        &mut self,
17762        _: &zed_actions::workspace::CopyRelativePath,
17763        _window: &mut Window,
17764        cx: &mut Context<Self>,
17765    ) {
17766        if let Some(path) = self.target_file_path(cx) {
17767            if let Some(path) = path.to_str() {
17768                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17769            }
17770        }
17771    }
17772
17773    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17774        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17775            buffer.read(cx).project_path(cx)
17776        } else {
17777            None
17778        }
17779    }
17780
17781    // Returns true if the editor handled a go-to-line request
17782    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17783        maybe!({
17784            let breakpoint_store = self.breakpoint_store.as_ref()?;
17785
17786            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17787            else {
17788                self.clear_row_highlights::<ActiveDebugLine>();
17789                return None;
17790            };
17791
17792            let position = active_stack_frame.position;
17793            let buffer_id = position.buffer_id?;
17794            let snapshot = self
17795                .project
17796                .as_ref()?
17797                .read(cx)
17798                .buffer_for_id(buffer_id, cx)?
17799                .read(cx)
17800                .snapshot();
17801
17802            let mut handled = false;
17803            for (id, ExcerptRange { context, .. }) in
17804                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17805            {
17806                if context.start.cmp(&position, &snapshot).is_ge()
17807                    || context.end.cmp(&position, &snapshot).is_lt()
17808                {
17809                    continue;
17810                }
17811                let snapshot = self.buffer.read(cx).snapshot(cx);
17812                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17813
17814                handled = true;
17815                self.clear_row_highlights::<ActiveDebugLine>();
17816
17817                self.go_to_line::<ActiveDebugLine>(
17818                    multibuffer_anchor,
17819                    Some(cx.theme().colors().editor_debugger_active_line_background),
17820                    window,
17821                    cx,
17822                );
17823
17824                cx.notify();
17825            }
17826
17827            handled.then_some(())
17828        })
17829        .is_some()
17830    }
17831
17832    pub fn copy_file_name_without_extension(
17833        &mut self,
17834        _: &CopyFileNameWithoutExtension,
17835        _: &mut Window,
17836        cx: &mut Context<Self>,
17837    ) {
17838        if let Some(file) = self.target_file(cx) {
17839            if let Some(file_stem) = file.path().file_stem() {
17840                if let Some(name) = file_stem.to_str() {
17841                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17842                }
17843            }
17844        }
17845    }
17846
17847    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17848        if let Some(file) = self.target_file(cx) {
17849            if let Some(file_name) = file.path().file_name() {
17850                if let Some(name) = file_name.to_str() {
17851                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17852                }
17853            }
17854        }
17855    }
17856
17857    pub fn toggle_git_blame(
17858        &mut self,
17859        _: &::git::Blame,
17860        window: &mut Window,
17861        cx: &mut Context<Self>,
17862    ) {
17863        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17864
17865        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17866            self.start_git_blame(true, window, cx);
17867        }
17868
17869        cx.notify();
17870    }
17871
17872    pub fn toggle_git_blame_inline(
17873        &mut self,
17874        _: &ToggleGitBlameInline,
17875        window: &mut Window,
17876        cx: &mut Context<Self>,
17877    ) {
17878        self.toggle_git_blame_inline_internal(true, window, cx);
17879        cx.notify();
17880    }
17881
17882    pub fn open_git_blame_commit(
17883        &mut self,
17884        _: &OpenGitBlameCommit,
17885        window: &mut Window,
17886        cx: &mut Context<Self>,
17887    ) {
17888        self.open_git_blame_commit_internal(window, cx);
17889    }
17890
17891    fn open_git_blame_commit_internal(
17892        &mut self,
17893        window: &mut Window,
17894        cx: &mut Context<Self>,
17895    ) -> Option<()> {
17896        let blame = self.blame.as_ref()?;
17897        let snapshot = self.snapshot(window, cx);
17898        let cursor = self.selections.newest::<Point>(cx).head();
17899        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17900        let blame_entry = blame
17901            .update(cx, |blame, cx| {
17902                blame
17903                    .blame_for_rows(
17904                        &[RowInfo {
17905                            buffer_id: Some(buffer.remote_id()),
17906                            buffer_row: Some(point.row),
17907                            ..Default::default()
17908                        }],
17909                        cx,
17910                    )
17911                    .next()
17912            })
17913            .flatten()?;
17914        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17915        let repo = blame.read(cx).repository(cx)?;
17916        let workspace = self.workspace()?.downgrade();
17917        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17918        None
17919    }
17920
17921    pub fn git_blame_inline_enabled(&self) -> bool {
17922        self.git_blame_inline_enabled
17923    }
17924
17925    pub fn toggle_selection_menu(
17926        &mut self,
17927        _: &ToggleSelectionMenu,
17928        _: &mut Window,
17929        cx: &mut Context<Self>,
17930    ) {
17931        self.show_selection_menu = self
17932            .show_selection_menu
17933            .map(|show_selections_menu| !show_selections_menu)
17934            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17935
17936        cx.notify();
17937    }
17938
17939    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17940        self.show_selection_menu
17941            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17942    }
17943
17944    fn start_git_blame(
17945        &mut self,
17946        user_triggered: bool,
17947        window: &mut Window,
17948        cx: &mut Context<Self>,
17949    ) {
17950        if let Some(project) = self.project.as_ref() {
17951            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17952                return;
17953            };
17954
17955            if buffer.read(cx).file().is_none() {
17956                return;
17957            }
17958
17959            let focused = self.focus_handle(cx).contains_focused(window, cx);
17960
17961            let project = project.clone();
17962            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17963            self.blame_subscription =
17964                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17965            self.blame = Some(blame);
17966        }
17967    }
17968
17969    fn toggle_git_blame_inline_internal(
17970        &mut self,
17971        user_triggered: bool,
17972        window: &mut Window,
17973        cx: &mut Context<Self>,
17974    ) {
17975        if self.git_blame_inline_enabled {
17976            self.git_blame_inline_enabled = false;
17977            self.show_git_blame_inline = false;
17978            self.show_git_blame_inline_delay_task.take();
17979        } else {
17980            self.git_blame_inline_enabled = true;
17981            self.start_git_blame_inline(user_triggered, window, cx);
17982        }
17983
17984        cx.notify();
17985    }
17986
17987    fn start_git_blame_inline(
17988        &mut self,
17989        user_triggered: bool,
17990        window: &mut Window,
17991        cx: &mut Context<Self>,
17992    ) {
17993        self.start_git_blame(user_triggered, window, cx);
17994
17995        if ProjectSettings::get_global(cx)
17996            .git
17997            .inline_blame_delay()
17998            .is_some()
17999        {
18000            self.start_inline_blame_timer(window, cx);
18001        } else {
18002            self.show_git_blame_inline = true
18003        }
18004    }
18005
18006    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18007        self.blame.as_ref()
18008    }
18009
18010    pub fn show_git_blame_gutter(&self) -> bool {
18011        self.show_git_blame_gutter
18012    }
18013
18014    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18015        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18016    }
18017
18018    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18019        self.show_git_blame_inline
18020            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18021            && !self.newest_selection_head_on_empty_line(cx)
18022            && self.has_blame_entries(cx)
18023    }
18024
18025    fn has_blame_entries(&self, cx: &App) -> bool {
18026        self.blame()
18027            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18028    }
18029
18030    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18031        let cursor_anchor = self.selections.newest_anchor().head();
18032
18033        let snapshot = self.buffer.read(cx).snapshot(cx);
18034        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18035
18036        snapshot.line_len(buffer_row) == 0
18037    }
18038
18039    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18040        let buffer_and_selection = maybe!({
18041            let selection = self.selections.newest::<Point>(cx);
18042            let selection_range = selection.range();
18043
18044            let multi_buffer = self.buffer().read(cx);
18045            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18046            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18047
18048            let (buffer, range, _) = if selection.reversed {
18049                buffer_ranges.first()
18050            } else {
18051                buffer_ranges.last()
18052            }?;
18053
18054            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18055                ..text::ToPoint::to_point(&range.end, &buffer).row;
18056            Some((
18057                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18058                selection,
18059            ))
18060        });
18061
18062        let Some((buffer, selection)) = buffer_and_selection else {
18063            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18064        };
18065
18066        let Some(project) = self.project.as_ref() else {
18067            return Task::ready(Err(anyhow!("editor does not have project")));
18068        };
18069
18070        project.update(cx, |project, cx| {
18071            project.get_permalink_to_line(&buffer, selection, cx)
18072        })
18073    }
18074
18075    pub fn copy_permalink_to_line(
18076        &mut self,
18077        _: &CopyPermalinkToLine,
18078        window: &mut Window,
18079        cx: &mut Context<Self>,
18080    ) {
18081        let permalink_task = self.get_permalink_to_line(cx);
18082        let workspace = self.workspace();
18083
18084        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18085            Ok(permalink) => {
18086                cx.update(|_, cx| {
18087                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18088                })
18089                .ok();
18090            }
18091            Err(err) => {
18092                let message = format!("Failed to copy permalink: {err}");
18093
18094                anyhow::Result::<()>::Err(err).log_err();
18095
18096                if let Some(workspace) = workspace {
18097                    workspace
18098                        .update_in(cx, |workspace, _, cx| {
18099                            struct CopyPermalinkToLine;
18100
18101                            workspace.show_toast(
18102                                Toast::new(
18103                                    NotificationId::unique::<CopyPermalinkToLine>(),
18104                                    message,
18105                                ),
18106                                cx,
18107                            )
18108                        })
18109                        .ok();
18110                }
18111            }
18112        })
18113        .detach();
18114    }
18115
18116    pub fn copy_file_location(
18117        &mut self,
18118        _: &CopyFileLocation,
18119        _: &mut Window,
18120        cx: &mut Context<Self>,
18121    ) {
18122        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18123        if let Some(file) = self.target_file(cx) {
18124            if let Some(path) = file.path().to_str() {
18125                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18126            }
18127        }
18128    }
18129
18130    pub fn open_permalink_to_line(
18131        &mut self,
18132        _: &OpenPermalinkToLine,
18133        window: &mut Window,
18134        cx: &mut Context<Self>,
18135    ) {
18136        let permalink_task = self.get_permalink_to_line(cx);
18137        let workspace = self.workspace();
18138
18139        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18140            Ok(permalink) => {
18141                cx.update(|_, cx| {
18142                    cx.open_url(permalink.as_ref());
18143                })
18144                .ok();
18145            }
18146            Err(err) => {
18147                let message = format!("Failed to open permalink: {err}");
18148
18149                anyhow::Result::<()>::Err(err).log_err();
18150
18151                if let Some(workspace) = workspace {
18152                    workspace
18153                        .update(cx, |workspace, cx| {
18154                            struct OpenPermalinkToLine;
18155
18156                            workspace.show_toast(
18157                                Toast::new(
18158                                    NotificationId::unique::<OpenPermalinkToLine>(),
18159                                    message,
18160                                ),
18161                                cx,
18162                            )
18163                        })
18164                        .ok();
18165                }
18166            }
18167        })
18168        .detach();
18169    }
18170
18171    pub fn insert_uuid_v4(
18172        &mut self,
18173        _: &InsertUuidV4,
18174        window: &mut Window,
18175        cx: &mut Context<Self>,
18176    ) {
18177        self.insert_uuid(UuidVersion::V4, window, cx);
18178    }
18179
18180    pub fn insert_uuid_v7(
18181        &mut self,
18182        _: &InsertUuidV7,
18183        window: &mut Window,
18184        cx: &mut Context<Self>,
18185    ) {
18186        self.insert_uuid(UuidVersion::V7, window, cx);
18187    }
18188
18189    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18190        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18191        self.transact(window, cx, |this, window, cx| {
18192            let edits = this
18193                .selections
18194                .all::<Point>(cx)
18195                .into_iter()
18196                .map(|selection| {
18197                    let uuid = match version {
18198                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18199                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18200                    };
18201
18202                    (selection.range(), uuid.to_string())
18203                });
18204            this.edit(edits, cx);
18205            this.refresh_inline_completion(true, false, window, cx);
18206        });
18207    }
18208
18209    pub fn open_selections_in_multibuffer(
18210        &mut self,
18211        _: &OpenSelectionsInMultibuffer,
18212        window: &mut Window,
18213        cx: &mut Context<Self>,
18214    ) {
18215        let multibuffer = self.buffer.read(cx);
18216
18217        let Some(buffer) = multibuffer.as_singleton() else {
18218            return;
18219        };
18220
18221        let Some(workspace) = self.workspace() else {
18222            return;
18223        };
18224
18225        let locations = self
18226            .selections
18227            .disjoint_anchors()
18228            .iter()
18229            .map(|range| Location {
18230                buffer: buffer.clone(),
18231                range: range.start.text_anchor..range.end.text_anchor,
18232            })
18233            .collect::<Vec<_>>();
18234
18235        let title = multibuffer.title(cx).to_string();
18236
18237        cx.spawn_in(window, async move |_, cx| {
18238            workspace.update_in(cx, |workspace, window, cx| {
18239                Self::open_locations_in_multibuffer(
18240                    workspace,
18241                    locations,
18242                    format!("Selections for '{title}'"),
18243                    false,
18244                    MultibufferSelectionMode::All,
18245                    window,
18246                    cx,
18247                );
18248            })
18249        })
18250        .detach();
18251    }
18252
18253    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18254    /// last highlight added will be used.
18255    ///
18256    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18257    pub fn highlight_rows<T: 'static>(
18258        &mut self,
18259        range: Range<Anchor>,
18260        color: Hsla,
18261        options: RowHighlightOptions,
18262        cx: &mut Context<Self>,
18263    ) {
18264        let snapshot = self.buffer().read(cx).snapshot(cx);
18265        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18266        let ix = row_highlights.binary_search_by(|highlight| {
18267            Ordering::Equal
18268                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18269                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18270        });
18271
18272        if let Err(mut ix) = ix {
18273            let index = post_inc(&mut self.highlight_order);
18274
18275            // If this range intersects with the preceding highlight, then merge it with
18276            // the preceding highlight. Otherwise insert a new highlight.
18277            let mut merged = false;
18278            if ix > 0 {
18279                let prev_highlight = &mut row_highlights[ix - 1];
18280                if prev_highlight
18281                    .range
18282                    .end
18283                    .cmp(&range.start, &snapshot)
18284                    .is_ge()
18285                {
18286                    ix -= 1;
18287                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18288                        prev_highlight.range.end = range.end;
18289                    }
18290                    merged = true;
18291                    prev_highlight.index = index;
18292                    prev_highlight.color = color;
18293                    prev_highlight.options = options;
18294                }
18295            }
18296
18297            if !merged {
18298                row_highlights.insert(
18299                    ix,
18300                    RowHighlight {
18301                        range: range.clone(),
18302                        index,
18303                        color,
18304                        options,
18305                        type_id: TypeId::of::<T>(),
18306                    },
18307                );
18308            }
18309
18310            // If any of the following highlights intersect with this one, merge them.
18311            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18312                let highlight = &row_highlights[ix];
18313                if next_highlight
18314                    .range
18315                    .start
18316                    .cmp(&highlight.range.end, &snapshot)
18317                    .is_le()
18318                {
18319                    if next_highlight
18320                        .range
18321                        .end
18322                        .cmp(&highlight.range.end, &snapshot)
18323                        .is_gt()
18324                    {
18325                        row_highlights[ix].range.end = next_highlight.range.end;
18326                    }
18327                    row_highlights.remove(ix + 1);
18328                } else {
18329                    break;
18330                }
18331            }
18332        }
18333    }
18334
18335    /// Remove any highlighted row ranges of the given type that intersect the
18336    /// given ranges.
18337    pub fn remove_highlighted_rows<T: 'static>(
18338        &mut self,
18339        ranges_to_remove: Vec<Range<Anchor>>,
18340        cx: &mut Context<Self>,
18341    ) {
18342        let snapshot = self.buffer().read(cx).snapshot(cx);
18343        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18344        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18345        row_highlights.retain(|highlight| {
18346            while let Some(range_to_remove) = ranges_to_remove.peek() {
18347                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18348                    Ordering::Less | Ordering::Equal => {
18349                        ranges_to_remove.next();
18350                    }
18351                    Ordering::Greater => {
18352                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18353                            Ordering::Less | Ordering::Equal => {
18354                                return false;
18355                            }
18356                            Ordering::Greater => break,
18357                        }
18358                    }
18359                }
18360            }
18361
18362            true
18363        })
18364    }
18365
18366    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18367    pub fn clear_row_highlights<T: 'static>(&mut self) {
18368        self.highlighted_rows.remove(&TypeId::of::<T>());
18369    }
18370
18371    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18372    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18373        self.highlighted_rows
18374            .get(&TypeId::of::<T>())
18375            .map_or(&[] as &[_], |vec| vec.as_slice())
18376            .iter()
18377            .map(|highlight| (highlight.range.clone(), highlight.color))
18378    }
18379
18380    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18381    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18382    /// Allows to ignore certain kinds of highlights.
18383    pub fn highlighted_display_rows(
18384        &self,
18385        window: &mut Window,
18386        cx: &mut App,
18387    ) -> BTreeMap<DisplayRow, LineHighlight> {
18388        let snapshot = self.snapshot(window, cx);
18389        let mut used_highlight_orders = HashMap::default();
18390        self.highlighted_rows
18391            .iter()
18392            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18393            .fold(
18394                BTreeMap::<DisplayRow, LineHighlight>::new(),
18395                |mut unique_rows, highlight| {
18396                    let start = highlight.range.start.to_display_point(&snapshot);
18397                    let end = highlight.range.end.to_display_point(&snapshot);
18398                    let start_row = start.row().0;
18399                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18400                        && end.column() == 0
18401                    {
18402                        end.row().0.saturating_sub(1)
18403                    } else {
18404                        end.row().0
18405                    };
18406                    for row in start_row..=end_row {
18407                        let used_index =
18408                            used_highlight_orders.entry(row).or_insert(highlight.index);
18409                        if highlight.index >= *used_index {
18410                            *used_index = highlight.index;
18411                            unique_rows.insert(
18412                                DisplayRow(row),
18413                                LineHighlight {
18414                                    include_gutter: highlight.options.include_gutter,
18415                                    border: None,
18416                                    background: highlight.color.into(),
18417                                    type_id: Some(highlight.type_id),
18418                                },
18419                            );
18420                        }
18421                    }
18422                    unique_rows
18423                },
18424            )
18425    }
18426
18427    pub fn highlighted_display_row_for_autoscroll(
18428        &self,
18429        snapshot: &DisplaySnapshot,
18430    ) -> Option<DisplayRow> {
18431        self.highlighted_rows
18432            .values()
18433            .flat_map(|highlighted_rows| highlighted_rows.iter())
18434            .filter_map(|highlight| {
18435                if highlight.options.autoscroll {
18436                    Some(highlight.range.start.to_display_point(snapshot).row())
18437                } else {
18438                    None
18439                }
18440            })
18441            .min()
18442    }
18443
18444    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18445        self.highlight_background::<SearchWithinRange>(
18446            ranges,
18447            |colors| colors.editor_document_highlight_read_background,
18448            cx,
18449        )
18450    }
18451
18452    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18453        self.breadcrumb_header = Some(new_header);
18454    }
18455
18456    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18457        self.clear_background_highlights::<SearchWithinRange>(cx);
18458    }
18459
18460    pub fn highlight_background<T: 'static>(
18461        &mut self,
18462        ranges: &[Range<Anchor>],
18463        color_fetcher: fn(&ThemeColors) -> Hsla,
18464        cx: &mut Context<Self>,
18465    ) {
18466        self.background_highlights
18467            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18468        self.scrollbar_marker_state.dirty = true;
18469        cx.notify();
18470    }
18471
18472    pub fn clear_background_highlights<T: 'static>(
18473        &mut self,
18474        cx: &mut Context<Self>,
18475    ) -> Option<BackgroundHighlight> {
18476        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18477        if !text_highlights.1.is_empty() {
18478            self.scrollbar_marker_state.dirty = true;
18479            cx.notify();
18480        }
18481        Some(text_highlights)
18482    }
18483
18484    pub fn highlight_gutter<T: 'static>(
18485        &mut self,
18486        ranges: impl Into<Vec<Range<Anchor>>>,
18487        color_fetcher: fn(&App) -> Hsla,
18488        cx: &mut Context<Self>,
18489    ) {
18490        self.gutter_highlights
18491            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18492        cx.notify();
18493    }
18494
18495    pub fn clear_gutter_highlights<T: 'static>(
18496        &mut self,
18497        cx: &mut Context<Self>,
18498    ) -> Option<GutterHighlight> {
18499        cx.notify();
18500        self.gutter_highlights.remove(&TypeId::of::<T>())
18501    }
18502
18503    pub fn insert_gutter_highlight<T: 'static>(
18504        &mut self,
18505        range: Range<Anchor>,
18506        color_fetcher: fn(&App) -> Hsla,
18507        cx: &mut Context<Self>,
18508    ) {
18509        let snapshot = self.buffer().read(cx).snapshot(cx);
18510        let mut highlights = self
18511            .gutter_highlights
18512            .remove(&TypeId::of::<T>())
18513            .map(|(_, highlights)| highlights)
18514            .unwrap_or_default();
18515        let ix = highlights.binary_search_by(|highlight| {
18516            Ordering::Equal
18517                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18518                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18519        });
18520        if let Err(ix) = ix {
18521            highlights.insert(ix, range);
18522        }
18523        self.gutter_highlights
18524            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18525    }
18526
18527    pub fn remove_gutter_highlights<T: 'static>(
18528        &mut self,
18529        ranges_to_remove: Vec<Range<Anchor>>,
18530        cx: &mut Context<Self>,
18531    ) {
18532        let snapshot = self.buffer().read(cx).snapshot(cx);
18533        let Some((color_fetcher, mut gutter_highlights)) =
18534            self.gutter_highlights.remove(&TypeId::of::<T>())
18535        else {
18536            return;
18537        };
18538        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18539        gutter_highlights.retain(|highlight| {
18540            while let Some(range_to_remove) = ranges_to_remove.peek() {
18541                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18542                    Ordering::Less | Ordering::Equal => {
18543                        ranges_to_remove.next();
18544                    }
18545                    Ordering::Greater => {
18546                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18547                            Ordering::Less | Ordering::Equal => {
18548                                return false;
18549                            }
18550                            Ordering::Greater => break,
18551                        }
18552                    }
18553                }
18554            }
18555
18556            true
18557        });
18558        self.gutter_highlights
18559            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18560    }
18561
18562    #[cfg(feature = "test-support")]
18563    pub fn all_text_background_highlights(
18564        &self,
18565        window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18568        let snapshot = self.snapshot(window, cx);
18569        let buffer = &snapshot.buffer_snapshot;
18570        let start = buffer.anchor_before(0);
18571        let end = buffer.anchor_after(buffer.len());
18572        let theme = cx.theme().colors();
18573        self.background_highlights_in_range(start..end, &snapshot, theme)
18574    }
18575
18576    #[cfg(feature = "test-support")]
18577    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18578        let snapshot = self.buffer().read(cx).snapshot(cx);
18579
18580        let highlights = self
18581            .background_highlights
18582            .get(&TypeId::of::<items::BufferSearchHighlights>());
18583
18584        if let Some((_color, ranges)) = highlights {
18585            ranges
18586                .iter()
18587                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18588                .collect_vec()
18589        } else {
18590            vec![]
18591        }
18592    }
18593
18594    fn document_highlights_for_position<'a>(
18595        &'a self,
18596        position: Anchor,
18597        buffer: &'a MultiBufferSnapshot,
18598    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18599        let read_highlights = self
18600            .background_highlights
18601            .get(&TypeId::of::<DocumentHighlightRead>())
18602            .map(|h| &h.1);
18603        let write_highlights = self
18604            .background_highlights
18605            .get(&TypeId::of::<DocumentHighlightWrite>())
18606            .map(|h| &h.1);
18607        let left_position = position.bias_left(buffer);
18608        let right_position = position.bias_right(buffer);
18609        read_highlights
18610            .into_iter()
18611            .chain(write_highlights)
18612            .flat_map(move |ranges| {
18613                let start_ix = match ranges.binary_search_by(|probe| {
18614                    let cmp = probe.end.cmp(&left_position, buffer);
18615                    if cmp.is_ge() {
18616                        Ordering::Greater
18617                    } else {
18618                        Ordering::Less
18619                    }
18620                }) {
18621                    Ok(i) | Err(i) => i,
18622                };
18623
18624                ranges[start_ix..]
18625                    .iter()
18626                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18627            })
18628    }
18629
18630    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18631        self.background_highlights
18632            .get(&TypeId::of::<T>())
18633            .map_or(false, |(_, highlights)| !highlights.is_empty())
18634    }
18635
18636    pub fn background_highlights_in_range(
18637        &self,
18638        search_range: Range<Anchor>,
18639        display_snapshot: &DisplaySnapshot,
18640        theme: &ThemeColors,
18641    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18642        let mut results = Vec::new();
18643        for (color_fetcher, ranges) in self.background_highlights.values() {
18644            let color = color_fetcher(theme);
18645            let start_ix = match ranges.binary_search_by(|probe| {
18646                let cmp = probe
18647                    .end
18648                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18649                if cmp.is_gt() {
18650                    Ordering::Greater
18651                } else {
18652                    Ordering::Less
18653                }
18654            }) {
18655                Ok(i) | Err(i) => i,
18656            };
18657            for range in &ranges[start_ix..] {
18658                if range
18659                    .start
18660                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18661                    .is_ge()
18662                {
18663                    break;
18664                }
18665
18666                let start = range.start.to_display_point(display_snapshot);
18667                let end = range.end.to_display_point(display_snapshot);
18668                results.push((start..end, color))
18669            }
18670        }
18671        results
18672    }
18673
18674    pub fn background_highlight_row_ranges<T: 'static>(
18675        &self,
18676        search_range: Range<Anchor>,
18677        display_snapshot: &DisplaySnapshot,
18678        count: usize,
18679    ) -> Vec<RangeInclusive<DisplayPoint>> {
18680        let mut results = Vec::new();
18681        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18682            return vec![];
18683        };
18684
18685        let start_ix = match ranges.binary_search_by(|probe| {
18686            let cmp = probe
18687                .end
18688                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18689            if cmp.is_gt() {
18690                Ordering::Greater
18691            } else {
18692                Ordering::Less
18693            }
18694        }) {
18695            Ok(i) | Err(i) => i,
18696        };
18697        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18698            if let (Some(start_display), Some(end_display)) = (start, end) {
18699                results.push(
18700                    start_display.to_display_point(display_snapshot)
18701                        ..=end_display.to_display_point(display_snapshot),
18702                );
18703            }
18704        };
18705        let mut start_row: Option<Point> = None;
18706        let mut end_row: Option<Point> = None;
18707        if ranges.len() > count {
18708            return Vec::new();
18709        }
18710        for range in &ranges[start_ix..] {
18711            if range
18712                .start
18713                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18714                .is_ge()
18715            {
18716                break;
18717            }
18718            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18719            if let Some(current_row) = &end_row {
18720                if end.row == current_row.row {
18721                    continue;
18722                }
18723            }
18724            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18725            if start_row.is_none() {
18726                assert_eq!(end_row, None);
18727                start_row = Some(start);
18728                end_row = Some(end);
18729                continue;
18730            }
18731            if let Some(current_end) = end_row.as_mut() {
18732                if start.row > current_end.row + 1 {
18733                    push_region(start_row, end_row);
18734                    start_row = Some(start);
18735                    end_row = Some(end);
18736                } else {
18737                    // Merge two hunks.
18738                    *current_end = end;
18739                }
18740            } else {
18741                unreachable!();
18742            }
18743        }
18744        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18745        push_region(start_row, end_row);
18746        results
18747    }
18748
18749    pub fn gutter_highlights_in_range(
18750        &self,
18751        search_range: Range<Anchor>,
18752        display_snapshot: &DisplaySnapshot,
18753        cx: &App,
18754    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18755        let mut results = Vec::new();
18756        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18757            let color = color_fetcher(cx);
18758            let start_ix = match ranges.binary_search_by(|probe| {
18759                let cmp = probe
18760                    .end
18761                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18762                if cmp.is_gt() {
18763                    Ordering::Greater
18764                } else {
18765                    Ordering::Less
18766                }
18767            }) {
18768                Ok(i) | Err(i) => i,
18769            };
18770            for range in &ranges[start_ix..] {
18771                if range
18772                    .start
18773                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18774                    .is_ge()
18775                {
18776                    break;
18777                }
18778
18779                let start = range.start.to_display_point(display_snapshot);
18780                let end = range.end.to_display_point(display_snapshot);
18781                results.push((start..end, color))
18782            }
18783        }
18784        results
18785    }
18786
18787    /// Get the text ranges corresponding to the redaction query
18788    pub fn redacted_ranges(
18789        &self,
18790        search_range: Range<Anchor>,
18791        display_snapshot: &DisplaySnapshot,
18792        cx: &App,
18793    ) -> Vec<Range<DisplayPoint>> {
18794        display_snapshot
18795            .buffer_snapshot
18796            .redacted_ranges(search_range, |file| {
18797                if let Some(file) = file {
18798                    file.is_private()
18799                        && EditorSettings::get(
18800                            Some(SettingsLocation {
18801                                worktree_id: file.worktree_id(cx),
18802                                path: file.path().as_ref(),
18803                            }),
18804                            cx,
18805                        )
18806                        .redact_private_values
18807                } else {
18808                    false
18809                }
18810            })
18811            .map(|range| {
18812                range.start.to_display_point(display_snapshot)
18813                    ..range.end.to_display_point(display_snapshot)
18814            })
18815            .collect()
18816    }
18817
18818    pub fn highlight_text<T: 'static>(
18819        &mut self,
18820        ranges: Vec<Range<Anchor>>,
18821        style: HighlightStyle,
18822        cx: &mut Context<Self>,
18823    ) {
18824        self.display_map.update(cx, |map, _| {
18825            map.highlight_text(TypeId::of::<T>(), ranges, style)
18826        });
18827        cx.notify();
18828    }
18829
18830    pub(crate) fn highlight_inlays<T: 'static>(
18831        &mut self,
18832        highlights: Vec<InlayHighlight>,
18833        style: HighlightStyle,
18834        cx: &mut Context<Self>,
18835    ) {
18836        self.display_map.update(cx, |map, _| {
18837            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18838        });
18839        cx.notify();
18840    }
18841
18842    pub fn text_highlights<'a, T: 'static>(
18843        &'a self,
18844        cx: &'a App,
18845    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18846        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18847    }
18848
18849    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18850        let cleared = self
18851            .display_map
18852            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18853        if cleared {
18854            cx.notify();
18855        }
18856    }
18857
18858    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18859        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18860            && self.focus_handle.is_focused(window)
18861    }
18862
18863    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18864        self.show_cursor_when_unfocused = is_enabled;
18865        cx.notify();
18866    }
18867
18868    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18869        cx.notify();
18870    }
18871
18872    fn on_debug_session_event(
18873        &mut self,
18874        _session: Entity<Session>,
18875        event: &SessionEvent,
18876        cx: &mut Context<Self>,
18877    ) {
18878        match event {
18879            SessionEvent::InvalidateInlineValue => {
18880                self.refresh_inline_values(cx);
18881            }
18882            _ => {}
18883        }
18884    }
18885
18886    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18887        let Some(project) = self.project.clone() else {
18888            return;
18889        };
18890
18891        if !self.inline_value_cache.enabled {
18892            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18893            self.splice_inlays(&inlays, Vec::new(), cx);
18894            return;
18895        }
18896
18897        let current_execution_position = self
18898            .highlighted_rows
18899            .get(&TypeId::of::<ActiveDebugLine>())
18900            .and_then(|lines| lines.last().map(|line| line.range.start));
18901
18902        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18903            let inline_values = editor
18904                .update(cx, |editor, cx| {
18905                    let Some(current_execution_position) = current_execution_position else {
18906                        return Some(Task::ready(Ok(Vec::new())));
18907                    };
18908
18909                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18910                        let snapshot = buffer.snapshot(cx);
18911
18912                        let excerpt = snapshot.excerpt_containing(
18913                            current_execution_position..current_execution_position,
18914                        )?;
18915
18916                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18917                    })?;
18918
18919                    let range =
18920                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18921
18922                    project.inline_values(buffer, range, cx)
18923                })
18924                .ok()
18925                .flatten()?
18926                .await
18927                .context("refreshing debugger inlays")
18928                .log_err()?;
18929
18930            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18931
18932            for (buffer_id, inline_value) in inline_values
18933                .into_iter()
18934                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18935            {
18936                buffer_inline_values
18937                    .entry(buffer_id)
18938                    .or_default()
18939                    .push(inline_value);
18940            }
18941
18942            editor
18943                .update(cx, |editor, cx| {
18944                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18945                    let mut new_inlays = Vec::default();
18946
18947                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18948                        let buffer_id = buffer_snapshot.remote_id();
18949                        buffer_inline_values
18950                            .get(&buffer_id)
18951                            .into_iter()
18952                            .flatten()
18953                            .for_each(|hint| {
18954                                let inlay = Inlay::debugger_hint(
18955                                    post_inc(&mut editor.next_inlay_id),
18956                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18957                                    hint.text(),
18958                                );
18959
18960                                new_inlays.push(inlay);
18961                            });
18962                    }
18963
18964                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18965                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18966
18967                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18968                })
18969                .ok()?;
18970            Some(())
18971        });
18972    }
18973
18974    fn on_buffer_event(
18975        &mut self,
18976        multibuffer: &Entity<MultiBuffer>,
18977        event: &multi_buffer::Event,
18978        window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        match event {
18982            multi_buffer::Event::Edited {
18983                singleton_buffer_edited,
18984                edited_buffer,
18985            } => {
18986                self.scrollbar_marker_state.dirty = true;
18987                self.active_indent_guides_state.dirty = true;
18988                self.refresh_active_diagnostics(cx);
18989                self.refresh_code_actions(window, cx);
18990                self.refresh_selected_text_highlights(true, window, cx);
18991                refresh_matching_bracket_highlights(self, window, cx);
18992                if self.has_active_inline_completion() {
18993                    self.update_visible_inline_completion(window, cx);
18994                }
18995                if let Some(project) = self.project.as_ref() {
18996                    if let Some(edited_buffer) = edited_buffer {
18997                        project.update(cx, |project, cx| {
18998                            self.registered_buffers
18999                                .entry(edited_buffer.read(cx).remote_id())
19000                                .or_insert_with(|| {
19001                                    project
19002                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19003                                });
19004                        });
19005                        if edited_buffer.read(cx).file().is_some() {
19006                            self.pull_diagnostics(
19007                                Some(edited_buffer.read(cx).remote_id()),
19008                                window,
19009                                cx,
19010                            );
19011                        }
19012                    }
19013                }
19014                cx.emit(EditorEvent::BufferEdited);
19015                cx.emit(SearchEvent::MatchesInvalidated);
19016                if *singleton_buffer_edited {
19017                    if let Some(buffer) = edited_buffer {
19018                        if buffer.read(cx).file().is_none() {
19019                            cx.emit(EditorEvent::TitleChanged);
19020                        }
19021                    }
19022                    if let Some(project) = &self.project {
19023                        #[allow(clippy::mutable_key_type)]
19024                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19025                            multibuffer
19026                                .all_buffers()
19027                                .into_iter()
19028                                .filter_map(|buffer| {
19029                                    buffer.update(cx, |buffer, cx| {
19030                                        let language = buffer.language()?;
19031                                        let should_discard = project.update(cx, |project, cx| {
19032                                            project.is_local()
19033                                                && !project.has_language_servers_for(buffer, cx)
19034                                        });
19035                                        should_discard.not().then_some(language.clone())
19036                                    })
19037                                })
19038                                .collect::<HashSet<_>>()
19039                        });
19040                        if !languages_affected.is_empty() {
19041                            self.refresh_inlay_hints(
19042                                InlayHintRefreshReason::BufferEdited(languages_affected),
19043                                cx,
19044                            );
19045                        }
19046                    }
19047                }
19048
19049                let Some(project) = &self.project else { return };
19050                let (telemetry, is_via_ssh) = {
19051                    let project = project.read(cx);
19052                    let telemetry = project.client().telemetry().clone();
19053                    let is_via_ssh = project.is_via_ssh();
19054                    (telemetry, is_via_ssh)
19055                };
19056                refresh_linked_ranges(self, window, cx);
19057                telemetry.log_edit_event("editor", is_via_ssh);
19058            }
19059            multi_buffer::Event::ExcerptsAdded {
19060                buffer,
19061                predecessor,
19062                excerpts,
19063            } => {
19064                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19065                let buffer_id = buffer.read(cx).remote_id();
19066                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19067                    if let Some(project) = &self.project {
19068                        update_uncommitted_diff_for_buffer(
19069                            cx.entity(),
19070                            project,
19071                            [buffer.clone()],
19072                            self.buffer.clone(),
19073                            cx,
19074                        )
19075                        .detach();
19076                    }
19077                }
19078                cx.emit(EditorEvent::ExcerptsAdded {
19079                    buffer: buffer.clone(),
19080                    predecessor: *predecessor,
19081                    excerpts: excerpts.clone(),
19082                });
19083                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19084            }
19085            multi_buffer::Event::ExcerptsRemoved {
19086                ids,
19087                removed_buffer_ids,
19088            } => {
19089                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19090                let buffer = self.buffer.read(cx);
19091                self.registered_buffers
19092                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19093                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19094                cx.emit(EditorEvent::ExcerptsRemoved {
19095                    ids: ids.clone(),
19096                    removed_buffer_ids: removed_buffer_ids.clone(),
19097                })
19098            }
19099            multi_buffer::Event::ExcerptsEdited {
19100                excerpt_ids,
19101                buffer_ids,
19102            } => {
19103                self.display_map.update(cx, |map, cx| {
19104                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19105                });
19106                cx.emit(EditorEvent::ExcerptsEdited {
19107                    ids: excerpt_ids.clone(),
19108                })
19109            }
19110            multi_buffer::Event::ExcerptsExpanded { ids } => {
19111                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19112                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19113            }
19114            multi_buffer::Event::Reparsed(buffer_id) => {
19115                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19116                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19117
19118                cx.emit(EditorEvent::Reparsed(*buffer_id));
19119            }
19120            multi_buffer::Event::DiffHunksToggled => {
19121                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19122            }
19123            multi_buffer::Event::LanguageChanged(buffer_id) => {
19124                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19125                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19126                cx.emit(EditorEvent::Reparsed(*buffer_id));
19127                cx.notify();
19128            }
19129            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19130            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19131            multi_buffer::Event::FileHandleChanged
19132            | multi_buffer::Event::Reloaded
19133            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19134            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19135            multi_buffer::Event::DiagnosticsUpdated => {
19136                self.update_diagnostics_state(window, cx);
19137            }
19138            _ => {}
19139        };
19140    }
19141
19142    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19143        self.refresh_active_diagnostics(cx);
19144        self.refresh_inline_diagnostics(true, window, cx);
19145        self.scrollbar_marker_state.dirty = true;
19146        cx.notify();
19147    }
19148
19149    pub fn start_temporary_diff_override(&mut self) {
19150        self.load_diff_task.take();
19151        self.temporary_diff_override = true;
19152    }
19153
19154    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19155        self.temporary_diff_override = false;
19156        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19157        self.buffer.update(cx, |buffer, cx| {
19158            buffer.set_all_diff_hunks_collapsed(cx);
19159        });
19160
19161        if let Some(project) = self.project.clone() {
19162            self.load_diff_task = Some(
19163                update_uncommitted_diff_for_buffer(
19164                    cx.entity(),
19165                    &project,
19166                    self.buffer.read(cx).all_buffers(),
19167                    self.buffer.clone(),
19168                    cx,
19169                )
19170                .shared(),
19171            );
19172        }
19173    }
19174
19175    fn on_display_map_changed(
19176        &mut self,
19177        _: Entity<DisplayMap>,
19178        _: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) {
19181        cx.notify();
19182    }
19183
19184    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19185        let new_severity = if self.diagnostics_enabled() {
19186            EditorSettings::get_global(cx)
19187                .diagnostics_max_severity
19188                .unwrap_or(DiagnosticSeverity::Hint)
19189        } else {
19190            DiagnosticSeverity::Off
19191        };
19192        self.set_max_diagnostics_severity(new_severity, cx);
19193        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19194        self.update_edit_prediction_settings(cx);
19195        self.refresh_inline_completion(true, false, window, cx);
19196        self.refresh_inlay_hints(
19197            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19198                self.selections.newest_anchor().head(),
19199                &self.buffer.read(cx).snapshot(cx),
19200                cx,
19201            )),
19202            cx,
19203        );
19204
19205        let old_cursor_shape = self.cursor_shape;
19206
19207        {
19208            let editor_settings = EditorSettings::get_global(cx);
19209            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19210            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19211            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19212            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19213            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19214        }
19215
19216        if old_cursor_shape != self.cursor_shape {
19217            cx.emit(EditorEvent::CursorShapeChanged);
19218        }
19219
19220        let project_settings = ProjectSettings::get_global(cx);
19221        self.serialize_dirty_buffers =
19222            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19223
19224        if self.mode.is_full() {
19225            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19226            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19227            if self.show_inline_diagnostics != show_inline_diagnostics {
19228                self.show_inline_diagnostics = show_inline_diagnostics;
19229                self.refresh_inline_diagnostics(false, window, cx);
19230            }
19231
19232            if self.git_blame_inline_enabled != inline_blame_enabled {
19233                self.toggle_git_blame_inline_internal(false, window, cx);
19234            }
19235
19236            let minimap_settings = EditorSettings::get_global(cx).minimap;
19237            if self.minimap_visibility != MinimapVisibility::Disabled {
19238                if self.minimap_visibility.settings_visibility()
19239                    != minimap_settings.minimap_enabled()
19240                {
19241                    self.set_minimap_visibility(
19242                        MinimapVisibility::for_mode(self.mode(), cx),
19243                        window,
19244                        cx,
19245                    );
19246                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19247                    minimap_entity.update(cx, |minimap_editor, cx| {
19248                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19249                    })
19250                }
19251            }
19252        }
19253
19254        cx.notify();
19255    }
19256
19257    pub fn set_searchable(&mut self, searchable: bool) {
19258        self.searchable = searchable;
19259    }
19260
19261    pub fn searchable(&self) -> bool {
19262        self.searchable
19263    }
19264
19265    fn open_proposed_changes_editor(
19266        &mut self,
19267        _: &OpenProposedChangesEditor,
19268        window: &mut Window,
19269        cx: &mut Context<Self>,
19270    ) {
19271        let Some(workspace) = self.workspace() else {
19272            cx.propagate();
19273            return;
19274        };
19275
19276        let selections = self.selections.all::<usize>(cx);
19277        let multi_buffer = self.buffer.read(cx);
19278        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19279        let mut new_selections_by_buffer = HashMap::default();
19280        for selection in selections {
19281            for (buffer, range, _) in
19282                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19283            {
19284                let mut range = range.to_point(buffer);
19285                range.start.column = 0;
19286                range.end.column = buffer.line_len(range.end.row);
19287                new_selections_by_buffer
19288                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19289                    .or_insert(Vec::new())
19290                    .push(range)
19291            }
19292        }
19293
19294        let proposed_changes_buffers = new_selections_by_buffer
19295            .into_iter()
19296            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19297            .collect::<Vec<_>>();
19298        let proposed_changes_editor = cx.new(|cx| {
19299            ProposedChangesEditor::new(
19300                "Proposed changes",
19301                proposed_changes_buffers,
19302                self.project.clone(),
19303                window,
19304                cx,
19305            )
19306        });
19307
19308        window.defer(cx, move |window, cx| {
19309            workspace.update(cx, |workspace, cx| {
19310                workspace.active_pane().update(cx, |pane, cx| {
19311                    pane.add_item(
19312                        Box::new(proposed_changes_editor),
19313                        true,
19314                        true,
19315                        None,
19316                        window,
19317                        cx,
19318                    );
19319                });
19320            });
19321        });
19322    }
19323
19324    pub fn open_excerpts_in_split(
19325        &mut self,
19326        _: &OpenExcerptsSplit,
19327        window: &mut Window,
19328        cx: &mut Context<Self>,
19329    ) {
19330        self.open_excerpts_common(None, true, window, cx)
19331    }
19332
19333    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19334        self.open_excerpts_common(None, false, window, cx)
19335    }
19336
19337    fn open_excerpts_common(
19338        &mut self,
19339        jump_data: Option<JumpData>,
19340        split: bool,
19341        window: &mut Window,
19342        cx: &mut Context<Self>,
19343    ) {
19344        let Some(workspace) = self.workspace() else {
19345            cx.propagate();
19346            return;
19347        };
19348
19349        if self.buffer.read(cx).is_singleton() {
19350            cx.propagate();
19351            return;
19352        }
19353
19354        let mut new_selections_by_buffer = HashMap::default();
19355        match &jump_data {
19356            Some(JumpData::MultiBufferPoint {
19357                excerpt_id,
19358                position,
19359                anchor,
19360                line_offset_from_top,
19361            }) => {
19362                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19363                if let Some(buffer) = multi_buffer_snapshot
19364                    .buffer_id_for_excerpt(*excerpt_id)
19365                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19366                {
19367                    let buffer_snapshot = buffer.read(cx).snapshot();
19368                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19369                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19370                    } else {
19371                        buffer_snapshot.clip_point(*position, Bias::Left)
19372                    };
19373                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19374                    new_selections_by_buffer.insert(
19375                        buffer,
19376                        (
19377                            vec![jump_to_offset..jump_to_offset],
19378                            Some(*line_offset_from_top),
19379                        ),
19380                    );
19381                }
19382            }
19383            Some(JumpData::MultiBufferRow {
19384                row,
19385                line_offset_from_top,
19386            }) => {
19387                let point = MultiBufferPoint::new(row.0, 0);
19388                if let Some((buffer, buffer_point, _)) =
19389                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19390                {
19391                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19392                    new_selections_by_buffer
19393                        .entry(buffer)
19394                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19395                        .0
19396                        .push(buffer_offset..buffer_offset)
19397                }
19398            }
19399            None => {
19400                let selections = self.selections.all::<usize>(cx);
19401                let multi_buffer = self.buffer.read(cx);
19402                for selection in selections {
19403                    for (snapshot, range, _, anchor) in multi_buffer
19404                        .snapshot(cx)
19405                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19406                    {
19407                        if let Some(anchor) = anchor {
19408                            // selection is in a deleted hunk
19409                            let Some(buffer_id) = anchor.buffer_id else {
19410                                continue;
19411                            };
19412                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19413                                continue;
19414                            };
19415                            let offset = text::ToOffset::to_offset(
19416                                &anchor.text_anchor,
19417                                &buffer_handle.read(cx).snapshot(),
19418                            );
19419                            let range = offset..offset;
19420                            new_selections_by_buffer
19421                                .entry(buffer_handle)
19422                                .or_insert((Vec::new(), None))
19423                                .0
19424                                .push(range)
19425                        } else {
19426                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19427                            else {
19428                                continue;
19429                            };
19430                            new_selections_by_buffer
19431                                .entry(buffer_handle)
19432                                .or_insert((Vec::new(), None))
19433                                .0
19434                                .push(range)
19435                        }
19436                    }
19437                }
19438            }
19439        }
19440
19441        new_selections_by_buffer
19442            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19443
19444        if new_selections_by_buffer.is_empty() {
19445            return;
19446        }
19447
19448        // We defer the pane interaction because we ourselves are a workspace item
19449        // and activating a new item causes the pane to call a method on us reentrantly,
19450        // which panics if we're on the stack.
19451        window.defer(cx, move |window, cx| {
19452            workspace.update(cx, |workspace, cx| {
19453                let pane = if split {
19454                    workspace.adjacent_pane(window, cx)
19455                } else {
19456                    workspace.active_pane().clone()
19457                };
19458
19459                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19460                    let editor = buffer
19461                        .read(cx)
19462                        .file()
19463                        .is_none()
19464                        .then(|| {
19465                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19466                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19467                            // Instead, we try to activate the existing editor in the pane first.
19468                            let (editor, pane_item_index) =
19469                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19470                                    let editor = item.downcast::<Editor>()?;
19471                                    let singleton_buffer =
19472                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19473                                    if singleton_buffer == buffer {
19474                                        Some((editor, i))
19475                                    } else {
19476                                        None
19477                                    }
19478                                })?;
19479                            pane.update(cx, |pane, cx| {
19480                                pane.activate_item(pane_item_index, true, true, window, cx)
19481                            });
19482                            Some(editor)
19483                        })
19484                        .flatten()
19485                        .unwrap_or_else(|| {
19486                            workspace.open_project_item::<Self>(
19487                                pane.clone(),
19488                                buffer,
19489                                true,
19490                                true,
19491                                window,
19492                                cx,
19493                            )
19494                        });
19495
19496                    editor.update(cx, |editor, cx| {
19497                        let autoscroll = match scroll_offset {
19498                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19499                            None => Autoscroll::newest(),
19500                        };
19501                        let nav_history = editor.nav_history.take();
19502                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19503                            s.select_ranges(ranges);
19504                        });
19505                        editor.nav_history = nav_history;
19506                    });
19507                }
19508            })
19509        });
19510    }
19511
19512    // For now, don't allow opening excerpts in buffers that aren't backed by
19513    // regular project files.
19514    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19515        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19516    }
19517
19518    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19519        let snapshot = self.buffer.read(cx).read(cx);
19520        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19521        Some(
19522            ranges
19523                .iter()
19524                .map(move |range| {
19525                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19526                })
19527                .collect(),
19528        )
19529    }
19530
19531    fn selection_replacement_ranges(
19532        &self,
19533        range: Range<OffsetUtf16>,
19534        cx: &mut App,
19535    ) -> Vec<Range<OffsetUtf16>> {
19536        let selections = self.selections.all::<OffsetUtf16>(cx);
19537        let newest_selection = selections
19538            .iter()
19539            .max_by_key(|selection| selection.id)
19540            .unwrap();
19541        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19542        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19543        let snapshot = self.buffer.read(cx).read(cx);
19544        selections
19545            .into_iter()
19546            .map(|mut selection| {
19547                selection.start.0 =
19548                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19549                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19550                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19551                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19552            })
19553            .collect()
19554    }
19555
19556    fn report_editor_event(
19557        &self,
19558        event_type: &'static str,
19559        file_extension: Option<String>,
19560        cx: &App,
19561    ) {
19562        if cfg!(any(test, feature = "test-support")) {
19563            return;
19564        }
19565
19566        let Some(project) = &self.project else { return };
19567
19568        // If None, we are in a file without an extension
19569        let file = self
19570            .buffer
19571            .read(cx)
19572            .as_singleton()
19573            .and_then(|b| b.read(cx).file());
19574        let file_extension = file_extension.or(file
19575            .as_ref()
19576            .and_then(|file| Path::new(file.file_name(cx)).extension())
19577            .and_then(|e| e.to_str())
19578            .map(|a| a.to_string()));
19579
19580        let vim_mode = vim_enabled(cx);
19581
19582        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19583        let copilot_enabled = edit_predictions_provider
19584            == language::language_settings::EditPredictionProvider::Copilot;
19585        let copilot_enabled_for_language = self
19586            .buffer
19587            .read(cx)
19588            .language_settings(cx)
19589            .show_edit_predictions;
19590
19591        let project = project.read(cx);
19592        telemetry::event!(
19593            event_type,
19594            file_extension,
19595            vim_mode,
19596            copilot_enabled,
19597            copilot_enabled_for_language,
19598            edit_predictions_provider,
19599            is_via_ssh = project.is_via_ssh(),
19600        );
19601    }
19602
19603    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19604    /// with each line being an array of {text, highlight} objects.
19605    fn copy_highlight_json(
19606        &mut self,
19607        _: &CopyHighlightJson,
19608        window: &mut Window,
19609        cx: &mut Context<Self>,
19610    ) {
19611        #[derive(Serialize)]
19612        struct Chunk<'a> {
19613            text: String,
19614            highlight: Option<&'a str>,
19615        }
19616
19617        let snapshot = self.buffer.read(cx).snapshot(cx);
19618        let range = self
19619            .selected_text_range(false, window, cx)
19620            .and_then(|selection| {
19621                if selection.range.is_empty() {
19622                    None
19623                } else {
19624                    Some(selection.range)
19625                }
19626            })
19627            .unwrap_or_else(|| 0..snapshot.len());
19628
19629        let chunks = snapshot.chunks(range, true);
19630        let mut lines = Vec::new();
19631        let mut line: VecDeque<Chunk> = VecDeque::new();
19632
19633        let Some(style) = self.style.as_ref() else {
19634            return;
19635        };
19636
19637        for chunk in chunks {
19638            let highlight = chunk
19639                .syntax_highlight_id
19640                .and_then(|id| id.name(&style.syntax));
19641            let mut chunk_lines = chunk.text.split('\n').peekable();
19642            while let Some(text) = chunk_lines.next() {
19643                let mut merged_with_last_token = false;
19644                if let Some(last_token) = line.back_mut() {
19645                    if last_token.highlight == highlight {
19646                        last_token.text.push_str(text);
19647                        merged_with_last_token = true;
19648                    }
19649                }
19650
19651                if !merged_with_last_token {
19652                    line.push_back(Chunk {
19653                        text: text.into(),
19654                        highlight,
19655                    });
19656                }
19657
19658                if chunk_lines.peek().is_some() {
19659                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19660                        line.pop_front();
19661                    }
19662                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19663                        line.pop_back();
19664                    }
19665
19666                    lines.push(mem::take(&mut line));
19667                }
19668            }
19669        }
19670
19671        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19672            return;
19673        };
19674        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19675    }
19676
19677    pub fn open_context_menu(
19678        &mut self,
19679        _: &OpenContextMenu,
19680        window: &mut Window,
19681        cx: &mut Context<Self>,
19682    ) {
19683        self.request_autoscroll(Autoscroll::newest(), cx);
19684        let position = self.selections.newest_display(cx).start;
19685        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19686    }
19687
19688    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19689        &self.inlay_hint_cache
19690    }
19691
19692    pub fn replay_insert_event(
19693        &mut self,
19694        text: &str,
19695        relative_utf16_range: Option<Range<isize>>,
19696        window: &mut Window,
19697        cx: &mut Context<Self>,
19698    ) {
19699        if !self.input_enabled {
19700            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19701            return;
19702        }
19703        if let Some(relative_utf16_range) = relative_utf16_range {
19704            let selections = self.selections.all::<OffsetUtf16>(cx);
19705            self.change_selections(None, window, cx, |s| {
19706                let new_ranges = selections.into_iter().map(|range| {
19707                    let start = OffsetUtf16(
19708                        range
19709                            .head()
19710                            .0
19711                            .saturating_add_signed(relative_utf16_range.start),
19712                    );
19713                    let end = OffsetUtf16(
19714                        range
19715                            .head()
19716                            .0
19717                            .saturating_add_signed(relative_utf16_range.end),
19718                    );
19719                    start..end
19720                });
19721                s.select_ranges(new_ranges);
19722            });
19723        }
19724
19725        self.handle_input(text, window, cx);
19726    }
19727
19728    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19729        let Some(provider) = self.semantics_provider.as_ref() else {
19730            return false;
19731        };
19732
19733        let mut supports = false;
19734        self.buffer().update(cx, |this, cx| {
19735            this.for_each_buffer(|buffer| {
19736                supports |= provider.supports_inlay_hints(buffer, cx);
19737            });
19738        });
19739
19740        supports
19741    }
19742
19743    pub fn is_focused(&self, window: &Window) -> bool {
19744        self.focus_handle.is_focused(window)
19745    }
19746
19747    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19748        cx.emit(EditorEvent::Focused);
19749
19750        if let Some(descendant) = self
19751            .last_focused_descendant
19752            .take()
19753            .and_then(|descendant| descendant.upgrade())
19754        {
19755            window.focus(&descendant);
19756        } else {
19757            if let Some(blame) = self.blame.as_ref() {
19758                blame.update(cx, GitBlame::focus)
19759            }
19760
19761            self.blink_manager.update(cx, BlinkManager::enable);
19762            self.show_cursor_names(window, cx);
19763            self.buffer.update(cx, |buffer, cx| {
19764                buffer.finalize_last_transaction(cx);
19765                if self.leader_id.is_none() {
19766                    buffer.set_active_selections(
19767                        &self.selections.disjoint_anchors(),
19768                        self.selections.line_mode,
19769                        self.cursor_shape,
19770                        cx,
19771                    );
19772                }
19773            });
19774        }
19775    }
19776
19777    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19778        cx.emit(EditorEvent::FocusedIn)
19779    }
19780
19781    fn handle_focus_out(
19782        &mut self,
19783        event: FocusOutEvent,
19784        _window: &mut Window,
19785        cx: &mut Context<Self>,
19786    ) {
19787        if event.blurred != self.focus_handle {
19788            self.last_focused_descendant = Some(event.blurred);
19789        }
19790        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19791    }
19792
19793    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19794        self.blink_manager.update(cx, BlinkManager::disable);
19795        self.buffer
19796            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19797
19798        if let Some(blame) = self.blame.as_ref() {
19799            blame.update(cx, GitBlame::blur)
19800        }
19801        if !self.hover_state.focused(window, cx) {
19802            hide_hover(self, cx);
19803        }
19804        if !self
19805            .context_menu
19806            .borrow()
19807            .as_ref()
19808            .is_some_and(|context_menu| context_menu.focused(window, cx))
19809        {
19810            self.hide_context_menu(window, cx);
19811        }
19812        self.discard_inline_completion(false, cx);
19813        cx.emit(EditorEvent::Blurred);
19814        cx.notify();
19815    }
19816
19817    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19818        let mut pending: String = window
19819            .pending_input_keystrokes()
19820            .into_iter()
19821            .flatten()
19822            .filter_map(|keystroke| {
19823                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19824                    keystroke.key_char.clone()
19825                } else {
19826                    None
19827                }
19828            })
19829            .collect();
19830
19831        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19832            pending = "".to_string();
19833        }
19834
19835        let existing_pending = self
19836            .text_highlights::<PendingInput>(cx)
19837            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19838        if existing_pending.is_none() && pending.is_empty() {
19839            return;
19840        }
19841        let transaction =
19842            self.transact(window, cx, |this, window, cx| {
19843                let selections = this.selections.all::<usize>(cx);
19844                let edits = selections
19845                    .iter()
19846                    .map(|selection| (selection.end..selection.end, pending.clone()));
19847                this.edit(edits, cx);
19848                this.change_selections(None, window, cx, |s| {
19849                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19850                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19851                    }));
19852                });
19853                if let Some(existing_ranges) = existing_pending {
19854                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19855                    this.edit(edits, cx);
19856                }
19857            });
19858
19859        let snapshot = self.snapshot(window, cx);
19860        let ranges = self
19861            .selections
19862            .all::<usize>(cx)
19863            .into_iter()
19864            .map(|selection| {
19865                snapshot.buffer_snapshot.anchor_after(selection.end)
19866                    ..snapshot
19867                        .buffer_snapshot
19868                        .anchor_before(selection.end + pending.len())
19869            })
19870            .collect();
19871
19872        if pending.is_empty() {
19873            self.clear_highlights::<PendingInput>(cx);
19874        } else {
19875            self.highlight_text::<PendingInput>(
19876                ranges,
19877                HighlightStyle {
19878                    underline: Some(UnderlineStyle {
19879                        thickness: px(1.),
19880                        color: None,
19881                        wavy: false,
19882                    }),
19883                    ..Default::default()
19884                },
19885                cx,
19886            );
19887        }
19888
19889        self.ime_transaction = self.ime_transaction.or(transaction);
19890        if let Some(transaction) = self.ime_transaction {
19891            self.buffer.update(cx, |buffer, cx| {
19892                buffer.group_until_transaction(transaction, cx);
19893            });
19894        }
19895
19896        if self.text_highlights::<PendingInput>(cx).is_none() {
19897            self.ime_transaction.take();
19898        }
19899    }
19900
19901    pub fn register_action_renderer(
19902        &mut self,
19903        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19904    ) -> Subscription {
19905        let id = self.next_editor_action_id.post_inc();
19906        self.editor_actions
19907            .borrow_mut()
19908            .insert(id, Box::new(listener));
19909
19910        let editor_actions = self.editor_actions.clone();
19911        Subscription::new(move || {
19912            editor_actions.borrow_mut().remove(&id);
19913        })
19914    }
19915
19916    pub fn register_action<A: Action>(
19917        &mut self,
19918        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19919    ) -> Subscription {
19920        let id = self.next_editor_action_id.post_inc();
19921        let listener = Arc::new(listener);
19922        self.editor_actions.borrow_mut().insert(
19923            id,
19924            Box::new(move |_, window, _| {
19925                let listener = listener.clone();
19926                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19927                    let action = action.downcast_ref().unwrap();
19928                    if phase == DispatchPhase::Bubble {
19929                        listener(action, window, cx)
19930                    }
19931                })
19932            }),
19933        );
19934
19935        let editor_actions = self.editor_actions.clone();
19936        Subscription::new(move || {
19937            editor_actions.borrow_mut().remove(&id);
19938        })
19939    }
19940
19941    pub fn file_header_size(&self) -> u32 {
19942        FILE_HEADER_HEIGHT
19943    }
19944
19945    pub fn restore(
19946        &mut self,
19947        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19948        window: &mut Window,
19949        cx: &mut Context<Self>,
19950    ) {
19951        let workspace = self.workspace();
19952        let project = self.project.as_ref();
19953        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19954            let mut tasks = Vec::new();
19955            for (buffer_id, changes) in revert_changes {
19956                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19957                    buffer.update(cx, |buffer, cx| {
19958                        buffer.edit(
19959                            changes
19960                                .into_iter()
19961                                .map(|(range, text)| (range, text.to_string())),
19962                            None,
19963                            cx,
19964                        );
19965                    });
19966
19967                    if let Some(project) =
19968                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19969                    {
19970                        project.update(cx, |project, cx| {
19971                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19972                        })
19973                    }
19974                }
19975            }
19976            tasks
19977        });
19978        cx.spawn_in(window, async move |_, cx| {
19979            for (buffer, task) in save_tasks {
19980                let result = task.await;
19981                if result.is_err() {
19982                    let Some(path) = buffer
19983                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19984                        .ok()
19985                    else {
19986                        continue;
19987                    };
19988                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19989                        let Some(task) = cx
19990                            .update_window_entity(&workspace, |workspace, window, cx| {
19991                                workspace
19992                                    .open_path_preview(path, None, false, false, false, window, cx)
19993                            })
19994                            .ok()
19995                        else {
19996                            continue;
19997                        };
19998                        task.await.log_err();
19999                    }
20000                }
20001            }
20002        })
20003        .detach();
20004        self.change_selections(None, window, cx, |selections| selections.refresh());
20005    }
20006
20007    pub fn to_pixel_point(
20008        &self,
20009        source: multi_buffer::Anchor,
20010        editor_snapshot: &EditorSnapshot,
20011        window: &mut Window,
20012    ) -> Option<gpui::Point<Pixels>> {
20013        let source_point = source.to_display_point(editor_snapshot);
20014        self.display_to_pixel_point(source_point, editor_snapshot, window)
20015    }
20016
20017    pub fn display_to_pixel_point(
20018        &self,
20019        source: DisplayPoint,
20020        editor_snapshot: &EditorSnapshot,
20021        window: &mut Window,
20022    ) -> Option<gpui::Point<Pixels>> {
20023        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20024        let text_layout_details = self.text_layout_details(window);
20025        let scroll_top = text_layout_details
20026            .scroll_anchor
20027            .scroll_position(editor_snapshot)
20028            .y;
20029
20030        if source.row().as_f32() < scroll_top.floor() {
20031            return None;
20032        }
20033        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20034        let source_y = line_height * (source.row().as_f32() - scroll_top);
20035        Some(gpui::Point::new(source_x, source_y))
20036    }
20037
20038    pub fn has_visible_completions_menu(&self) -> bool {
20039        !self.edit_prediction_preview_is_active()
20040            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20041                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20042            })
20043    }
20044
20045    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20046        if self.mode.is_minimap() {
20047            return;
20048        }
20049        self.addons
20050            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20051    }
20052
20053    pub fn unregister_addon<T: Addon>(&mut self) {
20054        self.addons.remove(&std::any::TypeId::of::<T>());
20055    }
20056
20057    pub fn addon<T: Addon>(&self) -> Option<&T> {
20058        let type_id = std::any::TypeId::of::<T>();
20059        self.addons
20060            .get(&type_id)
20061            .and_then(|item| item.to_any().downcast_ref::<T>())
20062    }
20063
20064    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20065        let type_id = std::any::TypeId::of::<T>();
20066        self.addons
20067            .get_mut(&type_id)
20068            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20069    }
20070
20071    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20072        let text_layout_details = self.text_layout_details(window);
20073        let style = &text_layout_details.editor_style;
20074        let font_id = window.text_system().resolve_font(&style.text.font());
20075        let font_size = style.text.font_size.to_pixels(window.rem_size());
20076        let line_height = style.text.line_height_in_pixels(window.rem_size());
20077        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20078
20079        gpui::Size::new(em_width, line_height)
20080    }
20081
20082    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20083        self.load_diff_task.clone()
20084    }
20085
20086    fn read_metadata_from_db(
20087        &mut self,
20088        item_id: u64,
20089        workspace_id: WorkspaceId,
20090        window: &mut Window,
20091        cx: &mut Context<Editor>,
20092    ) {
20093        if self.is_singleton(cx)
20094            && !self.mode.is_minimap()
20095            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20096        {
20097            let buffer_snapshot = OnceCell::new();
20098
20099            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20100                if !folds.is_empty() {
20101                    let snapshot =
20102                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20103                    self.fold_ranges(
20104                        folds
20105                            .into_iter()
20106                            .map(|(start, end)| {
20107                                snapshot.clip_offset(start, Bias::Left)
20108                                    ..snapshot.clip_offset(end, Bias::Right)
20109                            })
20110                            .collect(),
20111                        false,
20112                        window,
20113                        cx,
20114                    );
20115                }
20116            }
20117
20118            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20119                if !selections.is_empty() {
20120                    let snapshot =
20121                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20122                    // skip adding the initial selection to selection history
20123                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20124                    self.change_selections(None, window, cx, |s| {
20125                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20126                            snapshot.clip_offset(start, Bias::Left)
20127                                ..snapshot.clip_offset(end, Bias::Right)
20128                        }));
20129                    });
20130                    self.selection_history.mode = SelectionHistoryMode::Normal;
20131                }
20132            };
20133        }
20134
20135        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20136    }
20137}
20138
20139fn vim_enabled(cx: &App) -> bool {
20140    cx.global::<SettingsStore>()
20141        .raw_user_settings()
20142        .get("vim_mode")
20143        == Some(&serde_json::Value::Bool(true))
20144}
20145
20146fn process_completion_for_edit(
20147    completion: &Completion,
20148    intent: CompletionIntent,
20149    buffer: &Entity<Buffer>,
20150    cursor_position: &text::Anchor,
20151    cx: &mut Context<Editor>,
20152) -> CompletionEdit {
20153    let buffer = buffer.read(cx);
20154    let buffer_snapshot = buffer.snapshot();
20155    let (snippet, new_text) = if completion.is_snippet() {
20156        // Workaround for typescript language server issues so that methods don't expand within
20157        // strings and functions with type expressions. The previous point is used because the query
20158        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20159        let mut snippet_source = completion.new_text.clone();
20160        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20161        previous_point.column = previous_point.column.saturating_sub(1);
20162        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20163            if scope.prefers_label_for_snippet_in_completion() {
20164                if let Some(label) = completion.label() {
20165                    if matches!(
20166                        completion.kind(),
20167                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20168                    ) {
20169                        snippet_source = label;
20170                    }
20171                }
20172            }
20173        }
20174        match Snippet::parse(&snippet_source).log_err() {
20175            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20176            None => (None, completion.new_text.clone()),
20177        }
20178    } else {
20179        (None, completion.new_text.clone())
20180    };
20181
20182    let mut range_to_replace = {
20183        let replace_range = &completion.replace_range;
20184        if let CompletionSource::Lsp {
20185            insert_range: Some(insert_range),
20186            ..
20187        } = &completion.source
20188        {
20189            debug_assert_eq!(
20190                insert_range.start, replace_range.start,
20191                "insert_range and replace_range should start at the same position"
20192            );
20193            debug_assert!(
20194                insert_range
20195                    .start
20196                    .cmp(&cursor_position, &buffer_snapshot)
20197                    .is_le(),
20198                "insert_range should start before or at cursor position"
20199            );
20200            debug_assert!(
20201                replace_range
20202                    .start
20203                    .cmp(&cursor_position, &buffer_snapshot)
20204                    .is_le(),
20205                "replace_range should start before or at cursor position"
20206            );
20207            debug_assert!(
20208                insert_range
20209                    .end
20210                    .cmp(&cursor_position, &buffer_snapshot)
20211                    .is_le(),
20212                "insert_range should end before or at cursor position"
20213            );
20214
20215            let should_replace = match intent {
20216                CompletionIntent::CompleteWithInsert => false,
20217                CompletionIntent::CompleteWithReplace => true,
20218                CompletionIntent::Complete | CompletionIntent::Compose => {
20219                    let insert_mode =
20220                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20221                            .completions
20222                            .lsp_insert_mode;
20223                    match insert_mode {
20224                        LspInsertMode::Insert => false,
20225                        LspInsertMode::Replace => true,
20226                        LspInsertMode::ReplaceSubsequence => {
20227                            let mut text_to_replace = buffer.chars_for_range(
20228                                buffer.anchor_before(replace_range.start)
20229                                    ..buffer.anchor_after(replace_range.end),
20230                            );
20231                            let mut current_needle = text_to_replace.next();
20232                            for haystack_ch in completion.label.text.chars() {
20233                                if let Some(needle_ch) = current_needle {
20234                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20235                                        current_needle = text_to_replace.next();
20236                                    }
20237                                }
20238                            }
20239                            current_needle.is_none()
20240                        }
20241                        LspInsertMode::ReplaceSuffix => {
20242                            if replace_range
20243                                .end
20244                                .cmp(&cursor_position, &buffer_snapshot)
20245                                .is_gt()
20246                            {
20247                                let range_after_cursor = *cursor_position..replace_range.end;
20248                                let text_after_cursor = buffer
20249                                    .text_for_range(
20250                                        buffer.anchor_before(range_after_cursor.start)
20251                                            ..buffer.anchor_after(range_after_cursor.end),
20252                                    )
20253                                    .collect::<String>()
20254                                    .to_ascii_lowercase();
20255                                completion
20256                                    .label
20257                                    .text
20258                                    .to_ascii_lowercase()
20259                                    .ends_with(&text_after_cursor)
20260                            } else {
20261                                true
20262                            }
20263                        }
20264                    }
20265                }
20266            };
20267
20268            if should_replace {
20269                replace_range.clone()
20270            } else {
20271                insert_range.clone()
20272            }
20273        } else {
20274            replace_range.clone()
20275        }
20276    };
20277
20278    if range_to_replace
20279        .end
20280        .cmp(&cursor_position, &buffer_snapshot)
20281        .is_lt()
20282    {
20283        range_to_replace.end = *cursor_position;
20284    }
20285
20286    CompletionEdit {
20287        new_text,
20288        replace_range: range_to_replace.to_offset(&buffer),
20289        snippet,
20290    }
20291}
20292
20293struct CompletionEdit {
20294    new_text: String,
20295    replace_range: Range<usize>,
20296    snippet: Option<Snippet>,
20297}
20298
20299fn insert_extra_newline_brackets(
20300    buffer: &MultiBufferSnapshot,
20301    range: Range<usize>,
20302    language: &language::LanguageScope,
20303) -> bool {
20304    let leading_whitespace_len = buffer
20305        .reversed_chars_at(range.start)
20306        .take_while(|c| c.is_whitespace() && *c != '\n')
20307        .map(|c| c.len_utf8())
20308        .sum::<usize>();
20309    let trailing_whitespace_len = buffer
20310        .chars_at(range.end)
20311        .take_while(|c| c.is_whitespace() && *c != '\n')
20312        .map(|c| c.len_utf8())
20313        .sum::<usize>();
20314    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20315
20316    language.brackets().any(|(pair, enabled)| {
20317        let pair_start = pair.start.trim_end();
20318        let pair_end = pair.end.trim_start();
20319
20320        enabled
20321            && pair.newline
20322            && buffer.contains_str_at(range.end, pair_end)
20323            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20324    })
20325}
20326
20327fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20328    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20329        [(buffer, range, _)] => (*buffer, range.clone()),
20330        _ => return false,
20331    };
20332    let pair = {
20333        let mut result: Option<BracketMatch> = None;
20334
20335        for pair in buffer
20336            .all_bracket_ranges(range.clone())
20337            .filter(move |pair| {
20338                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20339            })
20340        {
20341            let len = pair.close_range.end - pair.open_range.start;
20342
20343            if let Some(existing) = &result {
20344                let existing_len = existing.close_range.end - existing.open_range.start;
20345                if len > existing_len {
20346                    continue;
20347                }
20348            }
20349
20350            result = Some(pair);
20351        }
20352
20353        result
20354    };
20355    let Some(pair) = pair else {
20356        return false;
20357    };
20358    pair.newline_only
20359        && buffer
20360            .chars_for_range(pair.open_range.end..range.start)
20361            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20362            .all(|c| c.is_whitespace() && c != '\n')
20363}
20364
20365fn update_uncommitted_diff_for_buffer(
20366    editor: Entity<Editor>,
20367    project: &Entity<Project>,
20368    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20369    buffer: Entity<MultiBuffer>,
20370    cx: &mut App,
20371) -> Task<()> {
20372    let mut tasks = Vec::new();
20373    project.update(cx, |project, cx| {
20374        for buffer in buffers {
20375            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20376                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20377            }
20378        }
20379    });
20380    cx.spawn(async move |cx| {
20381        let diffs = future::join_all(tasks).await;
20382        if editor
20383            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20384            .unwrap_or(false)
20385        {
20386            return;
20387        }
20388
20389        buffer
20390            .update(cx, |buffer, cx| {
20391                for diff in diffs.into_iter().flatten() {
20392                    buffer.add_diff(diff, cx);
20393                }
20394            })
20395            .ok();
20396    })
20397}
20398
20399fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20400    let tab_size = tab_size.get() as usize;
20401    let mut width = offset;
20402
20403    for ch in text.chars() {
20404        width += if ch == '\t' {
20405            tab_size - (width % tab_size)
20406        } else {
20407            1
20408        };
20409    }
20410
20411    width - offset
20412}
20413
20414#[cfg(test)]
20415mod tests {
20416    use super::*;
20417
20418    #[test]
20419    fn test_string_size_with_expanded_tabs() {
20420        let nz = |val| NonZeroU32::new(val).unwrap();
20421        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20422        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20423        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20424        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20425        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20426        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20427        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20428        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20429    }
20430}
20431
20432/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20433struct WordBreakingTokenizer<'a> {
20434    input: &'a str,
20435}
20436
20437impl<'a> WordBreakingTokenizer<'a> {
20438    fn new(input: &'a str) -> Self {
20439        Self { input }
20440    }
20441}
20442
20443fn is_char_ideographic(ch: char) -> bool {
20444    use unicode_script::Script::*;
20445    use unicode_script::UnicodeScript;
20446    matches!(ch.script(), Han | Tangut | Yi)
20447}
20448
20449fn is_grapheme_ideographic(text: &str) -> bool {
20450    text.chars().any(is_char_ideographic)
20451}
20452
20453fn is_grapheme_whitespace(text: &str) -> bool {
20454    text.chars().any(|x| x.is_whitespace())
20455}
20456
20457fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20458    text.chars().next().map_or(false, |ch| {
20459        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20460    })
20461}
20462
20463#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20464enum WordBreakToken<'a> {
20465    Word { token: &'a str, grapheme_len: usize },
20466    InlineWhitespace { token: &'a str, grapheme_len: usize },
20467    Newline,
20468}
20469
20470impl<'a> Iterator for WordBreakingTokenizer<'a> {
20471    /// Yields a span, the count of graphemes in the token, and whether it was
20472    /// whitespace. Note that it also breaks at word boundaries.
20473    type Item = WordBreakToken<'a>;
20474
20475    fn next(&mut self) -> Option<Self::Item> {
20476        use unicode_segmentation::UnicodeSegmentation;
20477        if self.input.is_empty() {
20478            return None;
20479        }
20480
20481        let mut iter = self.input.graphemes(true).peekable();
20482        let mut offset = 0;
20483        let mut grapheme_len = 0;
20484        if let Some(first_grapheme) = iter.next() {
20485            let is_newline = first_grapheme == "\n";
20486            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20487            offset += first_grapheme.len();
20488            grapheme_len += 1;
20489            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20490                if let Some(grapheme) = iter.peek().copied() {
20491                    if should_stay_with_preceding_ideograph(grapheme) {
20492                        offset += grapheme.len();
20493                        grapheme_len += 1;
20494                    }
20495                }
20496            } else {
20497                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20498                let mut next_word_bound = words.peek().copied();
20499                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20500                    next_word_bound = words.next();
20501                }
20502                while let Some(grapheme) = iter.peek().copied() {
20503                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20504                        break;
20505                    };
20506                    if is_grapheme_whitespace(grapheme) != is_whitespace
20507                        || (grapheme == "\n") != is_newline
20508                    {
20509                        break;
20510                    };
20511                    offset += grapheme.len();
20512                    grapheme_len += 1;
20513                    iter.next();
20514                }
20515            }
20516            let token = &self.input[..offset];
20517            self.input = &self.input[offset..];
20518            if token == "\n" {
20519                Some(WordBreakToken::Newline)
20520            } else if is_whitespace {
20521                Some(WordBreakToken::InlineWhitespace {
20522                    token,
20523                    grapheme_len,
20524                })
20525            } else {
20526                Some(WordBreakToken::Word {
20527                    token,
20528                    grapheme_len,
20529                })
20530            }
20531        } else {
20532            None
20533        }
20534    }
20535}
20536
20537#[test]
20538fn test_word_breaking_tokenizer() {
20539    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20540        ("", &[]),
20541        ("  ", &[whitespace("  ", 2)]),
20542        ("Ʒ", &[word("Ʒ", 1)]),
20543        ("Ǽ", &[word("Ǽ", 1)]),
20544        ("", &[word("", 1)]),
20545        ("⋑⋑", &[word("⋑⋑", 2)]),
20546        (
20547            "原理,进而",
20548            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20549        ),
20550        (
20551            "hello world",
20552            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20553        ),
20554        (
20555            "hello, world",
20556            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20557        ),
20558        (
20559            "  hello world",
20560            &[
20561                whitespace("  ", 2),
20562                word("hello", 5),
20563                whitespace(" ", 1),
20564                word("world", 5),
20565            ],
20566        ),
20567        (
20568            "这是什么 \n 钢笔",
20569            &[
20570                word("", 1),
20571                word("", 1),
20572                word("", 1),
20573                word("", 1),
20574                whitespace(" ", 1),
20575                newline(),
20576                whitespace(" ", 1),
20577                word("", 1),
20578                word("", 1),
20579            ],
20580        ),
20581        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20582    ];
20583
20584    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20585        WordBreakToken::Word {
20586            token,
20587            grapheme_len,
20588        }
20589    }
20590
20591    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20592        WordBreakToken::InlineWhitespace {
20593            token,
20594            grapheme_len,
20595        }
20596    }
20597
20598    fn newline() -> WordBreakToken<'static> {
20599        WordBreakToken::Newline
20600    }
20601
20602    for (input, result) in tests {
20603        assert_eq!(
20604            WordBreakingTokenizer::new(input)
20605                .collect::<Vec<_>>()
20606                .as_slice(),
20607            *result,
20608        );
20609    }
20610}
20611
20612fn wrap_with_prefix(
20613    line_prefix: String,
20614    unwrapped_text: String,
20615    wrap_column: usize,
20616    tab_size: NonZeroU32,
20617    preserve_existing_whitespace: bool,
20618) -> String {
20619    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20620    let mut wrapped_text = String::new();
20621    let mut current_line = line_prefix.clone();
20622
20623    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20624    let mut current_line_len = line_prefix_len;
20625    let mut in_whitespace = false;
20626    for token in tokenizer {
20627        let have_preceding_whitespace = in_whitespace;
20628        match token {
20629            WordBreakToken::Word {
20630                token,
20631                grapheme_len,
20632            } => {
20633                in_whitespace = false;
20634                if current_line_len + grapheme_len > wrap_column
20635                    && current_line_len != line_prefix_len
20636                {
20637                    wrapped_text.push_str(current_line.trim_end());
20638                    wrapped_text.push('\n');
20639                    current_line.truncate(line_prefix.len());
20640                    current_line_len = line_prefix_len;
20641                }
20642                current_line.push_str(token);
20643                current_line_len += grapheme_len;
20644            }
20645            WordBreakToken::InlineWhitespace {
20646                mut token,
20647                mut grapheme_len,
20648            } => {
20649                in_whitespace = true;
20650                if have_preceding_whitespace && !preserve_existing_whitespace {
20651                    continue;
20652                }
20653                if !preserve_existing_whitespace {
20654                    token = " ";
20655                    grapheme_len = 1;
20656                }
20657                if current_line_len + grapheme_len > wrap_column {
20658                    wrapped_text.push_str(current_line.trim_end());
20659                    wrapped_text.push('\n');
20660                    current_line.truncate(line_prefix.len());
20661                    current_line_len = line_prefix_len;
20662                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20663                    current_line.push_str(token);
20664                    current_line_len += grapheme_len;
20665                }
20666            }
20667            WordBreakToken::Newline => {
20668                in_whitespace = true;
20669                if preserve_existing_whitespace {
20670                    wrapped_text.push_str(current_line.trim_end());
20671                    wrapped_text.push('\n');
20672                    current_line.truncate(line_prefix.len());
20673                    current_line_len = line_prefix_len;
20674                } else if have_preceding_whitespace {
20675                    continue;
20676                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20677                {
20678                    wrapped_text.push_str(current_line.trim_end());
20679                    wrapped_text.push('\n');
20680                    current_line.truncate(line_prefix.len());
20681                    current_line_len = line_prefix_len;
20682                } else if current_line_len != line_prefix_len {
20683                    current_line.push(' ');
20684                    current_line_len += 1;
20685                }
20686            }
20687        }
20688    }
20689
20690    if !current_line.is_empty() {
20691        wrapped_text.push_str(&current_line);
20692    }
20693    wrapped_text
20694}
20695
20696#[test]
20697fn test_wrap_with_prefix() {
20698    assert_eq!(
20699        wrap_with_prefix(
20700            "# ".to_string(),
20701            "abcdefg".to_string(),
20702            4,
20703            NonZeroU32::new(4).unwrap(),
20704            false,
20705        ),
20706        "# abcdefg"
20707    );
20708    assert_eq!(
20709        wrap_with_prefix(
20710            "".to_string(),
20711            "\thello world".to_string(),
20712            8,
20713            NonZeroU32::new(4).unwrap(),
20714            false,
20715        ),
20716        "hello\nworld"
20717    );
20718    assert_eq!(
20719        wrap_with_prefix(
20720            "// ".to_string(),
20721            "xx \nyy zz aa bb cc".to_string(),
20722            12,
20723            NonZeroU32::new(4).unwrap(),
20724            false,
20725        ),
20726        "// xx yy zz\n// aa bb cc"
20727    );
20728    assert_eq!(
20729        wrap_with_prefix(
20730            String::new(),
20731            "这是什么 \n 钢笔".to_string(),
20732            3,
20733            NonZeroU32::new(4).unwrap(),
20734            false,
20735        ),
20736        "这是什\n么 钢\n"
20737    );
20738}
20739
20740pub trait CollaborationHub {
20741    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20742    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20743    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20744}
20745
20746impl CollaborationHub for Entity<Project> {
20747    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20748        self.read(cx).collaborators()
20749    }
20750
20751    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20752        self.read(cx).user_store().read(cx).participant_indices()
20753    }
20754
20755    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20756        let this = self.read(cx);
20757        let user_ids = this.collaborators().values().map(|c| c.user_id);
20758        this.user_store().read(cx).participant_names(user_ids, cx)
20759    }
20760}
20761
20762pub trait SemanticsProvider {
20763    fn hover(
20764        &self,
20765        buffer: &Entity<Buffer>,
20766        position: text::Anchor,
20767        cx: &mut App,
20768    ) -> Option<Task<Vec<project::Hover>>>;
20769
20770    fn inline_values(
20771        &self,
20772        buffer_handle: Entity<Buffer>,
20773        range: Range<text::Anchor>,
20774        cx: &mut App,
20775    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20776
20777    fn inlay_hints(
20778        &self,
20779        buffer_handle: Entity<Buffer>,
20780        range: Range<text::Anchor>,
20781        cx: &mut App,
20782    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20783
20784    fn resolve_inlay_hint(
20785        &self,
20786        hint: InlayHint,
20787        buffer_handle: Entity<Buffer>,
20788        server_id: LanguageServerId,
20789        cx: &mut App,
20790    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20791
20792    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20793
20794    fn document_highlights(
20795        &self,
20796        buffer: &Entity<Buffer>,
20797        position: text::Anchor,
20798        cx: &mut App,
20799    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20800
20801    fn definitions(
20802        &self,
20803        buffer: &Entity<Buffer>,
20804        position: text::Anchor,
20805        kind: GotoDefinitionKind,
20806        cx: &mut App,
20807    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20808
20809    fn range_for_rename(
20810        &self,
20811        buffer: &Entity<Buffer>,
20812        position: text::Anchor,
20813        cx: &mut App,
20814    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20815
20816    fn perform_rename(
20817        &self,
20818        buffer: &Entity<Buffer>,
20819        position: text::Anchor,
20820        new_name: String,
20821        cx: &mut App,
20822    ) -> Option<Task<Result<ProjectTransaction>>>;
20823
20824    fn pull_diagnostics_for_buffer(
20825        &self,
20826        buffer: Entity<Buffer>,
20827        cx: &mut App,
20828    ) -> Task<anyhow::Result<()>>;
20829}
20830
20831pub trait CompletionProvider {
20832    fn completions(
20833        &self,
20834        excerpt_id: ExcerptId,
20835        buffer: &Entity<Buffer>,
20836        buffer_position: text::Anchor,
20837        trigger: CompletionContext,
20838        window: &mut Window,
20839        cx: &mut Context<Editor>,
20840    ) -> Task<Result<Vec<CompletionResponse>>>;
20841
20842    fn resolve_completions(
20843        &self,
20844        _buffer: Entity<Buffer>,
20845        _completion_indices: Vec<usize>,
20846        _completions: Rc<RefCell<Box<[Completion]>>>,
20847        _cx: &mut Context<Editor>,
20848    ) -> Task<Result<bool>> {
20849        Task::ready(Ok(false))
20850    }
20851
20852    fn apply_additional_edits_for_completion(
20853        &self,
20854        _buffer: Entity<Buffer>,
20855        _completions: Rc<RefCell<Box<[Completion]>>>,
20856        _completion_index: usize,
20857        _push_to_history: bool,
20858        _cx: &mut Context<Editor>,
20859    ) -> Task<Result<Option<language::Transaction>>> {
20860        Task::ready(Ok(None))
20861    }
20862
20863    fn is_completion_trigger(
20864        &self,
20865        buffer: &Entity<Buffer>,
20866        position: language::Anchor,
20867        text: &str,
20868        trigger_in_words: bool,
20869        menu_is_open: bool,
20870        cx: &mut Context<Editor>,
20871    ) -> bool;
20872
20873    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20874
20875    fn sort_completions(&self) -> bool {
20876        true
20877    }
20878
20879    fn filter_completions(&self) -> bool {
20880        true
20881    }
20882}
20883
20884pub trait CodeActionProvider {
20885    fn id(&self) -> Arc<str>;
20886
20887    fn code_actions(
20888        &self,
20889        buffer: &Entity<Buffer>,
20890        range: Range<text::Anchor>,
20891        window: &mut Window,
20892        cx: &mut App,
20893    ) -> Task<Result<Vec<CodeAction>>>;
20894
20895    fn apply_code_action(
20896        &self,
20897        buffer_handle: Entity<Buffer>,
20898        action: CodeAction,
20899        excerpt_id: ExcerptId,
20900        push_to_history: bool,
20901        window: &mut Window,
20902        cx: &mut App,
20903    ) -> Task<Result<ProjectTransaction>>;
20904}
20905
20906impl CodeActionProvider for Entity<Project> {
20907    fn id(&self) -> Arc<str> {
20908        "project".into()
20909    }
20910
20911    fn code_actions(
20912        &self,
20913        buffer: &Entity<Buffer>,
20914        range: Range<text::Anchor>,
20915        _window: &mut Window,
20916        cx: &mut App,
20917    ) -> Task<Result<Vec<CodeAction>>> {
20918        self.update(cx, |project, cx| {
20919            let code_lens = project.code_lens(buffer, range.clone(), cx);
20920            let code_actions = project.code_actions(buffer, range, None, cx);
20921            cx.background_spawn(async move {
20922                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20923                Ok(code_lens
20924                    .context("code lens fetch")?
20925                    .into_iter()
20926                    .chain(code_actions.context("code action fetch")?)
20927                    .collect())
20928            })
20929        })
20930    }
20931
20932    fn apply_code_action(
20933        &self,
20934        buffer_handle: Entity<Buffer>,
20935        action: CodeAction,
20936        _excerpt_id: ExcerptId,
20937        push_to_history: bool,
20938        _window: &mut Window,
20939        cx: &mut App,
20940    ) -> Task<Result<ProjectTransaction>> {
20941        self.update(cx, |project, cx| {
20942            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20943        })
20944    }
20945}
20946
20947fn snippet_completions(
20948    project: &Project,
20949    buffer: &Entity<Buffer>,
20950    buffer_position: text::Anchor,
20951    cx: &mut App,
20952) -> Task<Result<CompletionResponse>> {
20953    let languages = buffer.read(cx).languages_at(buffer_position);
20954    let snippet_store = project.snippets().read(cx);
20955
20956    let scopes: Vec<_> = languages
20957        .iter()
20958        .filter_map(|language| {
20959            let language_name = language.lsp_id();
20960            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20961
20962            if snippets.is_empty() {
20963                None
20964            } else {
20965                Some((language.default_scope(), snippets))
20966            }
20967        })
20968        .collect();
20969
20970    if scopes.is_empty() {
20971        return Task::ready(Ok(CompletionResponse {
20972            completions: vec![],
20973            is_incomplete: false,
20974        }));
20975    }
20976
20977    let snapshot = buffer.read(cx).text_snapshot();
20978    let chars: String = snapshot
20979        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20980        .collect();
20981    let executor = cx.background_executor().clone();
20982
20983    cx.background_spawn(async move {
20984        let mut is_incomplete = false;
20985        let mut completions: Vec<Completion> = Vec::new();
20986        for (scope, snippets) in scopes.into_iter() {
20987            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20988            let mut last_word = chars
20989                .chars()
20990                .take_while(|c| classifier.is_word(*c))
20991                .collect::<String>();
20992            last_word = last_word.chars().rev().collect();
20993
20994            if last_word.is_empty() {
20995                return Ok(CompletionResponse {
20996                    completions: vec![],
20997                    is_incomplete: true,
20998                });
20999            }
21000
21001            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21002            let to_lsp = |point: &text::Anchor| {
21003                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21004                point_to_lsp(end)
21005            };
21006            let lsp_end = to_lsp(&buffer_position);
21007
21008            let candidates = snippets
21009                .iter()
21010                .enumerate()
21011                .flat_map(|(ix, snippet)| {
21012                    snippet
21013                        .prefix
21014                        .iter()
21015                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21016                })
21017                .collect::<Vec<StringMatchCandidate>>();
21018
21019            const MAX_RESULTS: usize = 100;
21020            let mut matches = fuzzy::match_strings(
21021                &candidates,
21022                &last_word,
21023                last_word.chars().any(|c| c.is_uppercase()),
21024                MAX_RESULTS,
21025                &Default::default(),
21026                executor.clone(),
21027            )
21028            .await;
21029
21030            if matches.len() >= MAX_RESULTS {
21031                is_incomplete = true;
21032            }
21033
21034            // Remove all candidates where the query's start does not match the start of any word in the candidate
21035            if let Some(query_start) = last_word.chars().next() {
21036                matches.retain(|string_match| {
21037                    split_words(&string_match.string).any(|word| {
21038                        // Check that the first codepoint of the word as lowercase matches the first
21039                        // codepoint of the query as lowercase
21040                        word.chars()
21041                            .flat_map(|codepoint| codepoint.to_lowercase())
21042                            .zip(query_start.to_lowercase())
21043                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21044                    })
21045                });
21046            }
21047
21048            let matched_strings = matches
21049                .into_iter()
21050                .map(|m| m.string)
21051                .collect::<HashSet<_>>();
21052
21053            completions.extend(snippets.iter().filter_map(|snippet| {
21054                let matching_prefix = snippet
21055                    .prefix
21056                    .iter()
21057                    .find(|prefix| matched_strings.contains(*prefix))?;
21058                let start = as_offset - last_word.len();
21059                let start = snapshot.anchor_before(start);
21060                let range = start..buffer_position;
21061                let lsp_start = to_lsp(&start);
21062                let lsp_range = lsp::Range {
21063                    start: lsp_start,
21064                    end: lsp_end,
21065                };
21066                Some(Completion {
21067                    replace_range: range,
21068                    new_text: snippet.body.clone(),
21069                    source: CompletionSource::Lsp {
21070                        insert_range: None,
21071                        server_id: LanguageServerId(usize::MAX),
21072                        resolved: true,
21073                        lsp_completion: Box::new(lsp::CompletionItem {
21074                            label: snippet.prefix.first().unwrap().clone(),
21075                            kind: Some(CompletionItemKind::SNIPPET),
21076                            label_details: snippet.description.as_ref().map(|description| {
21077                                lsp::CompletionItemLabelDetails {
21078                                    detail: Some(description.clone()),
21079                                    description: None,
21080                                }
21081                            }),
21082                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21083                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21084                                lsp::InsertReplaceEdit {
21085                                    new_text: snippet.body.clone(),
21086                                    insert: lsp_range,
21087                                    replace: lsp_range,
21088                                },
21089                            )),
21090                            filter_text: Some(snippet.body.clone()),
21091                            sort_text: Some(char::MAX.to_string()),
21092                            ..lsp::CompletionItem::default()
21093                        }),
21094                        lsp_defaults: None,
21095                    },
21096                    label: CodeLabel {
21097                        text: matching_prefix.clone(),
21098                        runs: Vec::new(),
21099                        filter_range: 0..matching_prefix.len(),
21100                    },
21101                    icon_path: None,
21102                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21103                        single_line: snippet.name.clone().into(),
21104                        plain_text: snippet
21105                            .description
21106                            .clone()
21107                            .map(|description| description.into()),
21108                    }),
21109                    insert_text_mode: None,
21110                    confirm: None,
21111                })
21112            }))
21113        }
21114
21115        Ok(CompletionResponse {
21116            completions,
21117            is_incomplete,
21118        })
21119    })
21120}
21121
21122impl CompletionProvider for Entity<Project> {
21123    fn completions(
21124        &self,
21125        _excerpt_id: ExcerptId,
21126        buffer: &Entity<Buffer>,
21127        buffer_position: text::Anchor,
21128        options: CompletionContext,
21129        _window: &mut Window,
21130        cx: &mut Context<Editor>,
21131    ) -> Task<Result<Vec<CompletionResponse>>> {
21132        self.update(cx, |project, cx| {
21133            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21134            let project_completions = project.completions(buffer, buffer_position, options, cx);
21135            cx.background_spawn(async move {
21136                let mut responses = project_completions.await?;
21137                let snippets = snippets.await?;
21138                if !snippets.completions.is_empty() {
21139                    responses.push(snippets);
21140                }
21141                Ok(responses)
21142            })
21143        })
21144    }
21145
21146    fn resolve_completions(
21147        &self,
21148        buffer: Entity<Buffer>,
21149        completion_indices: Vec<usize>,
21150        completions: Rc<RefCell<Box<[Completion]>>>,
21151        cx: &mut Context<Editor>,
21152    ) -> Task<Result<bool>> {
21153        self.update(cx, |project, cx| {
21154            project.lsp_store().update(cx, |lsp_store, cx| {
21155                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21156            })
21157        })
21158    }
21159
21160    fn apply_additional_edits_for_completion(
21161        &self,
21162        buffer: Entity<Buffer>,
21163        completions: Rc<RefCell<Box<[Completion]>>>,
21164        completion_index: usize,
21165        push_to_history: bool,
21166        cx: &mut Context<Editor>,
21167    ) -> Task<Result<Option<language::Transaction>>> {
21168        self.update(cx, |project, cx| {
21169            project.lsp_store().update(cx, |lsp_store, cx| {
21170                lsp_store.apply_additional_edits_for_completion(
21171                    buffer,
21172                    completions,
21173                    completion_index,
21174                    push_to_history,
21175                    cx,
21176                )
21177            })
21178        })
21179    }
21180
21181    fn is_completion_trigger(
21182        &self,
21183        buffer: &Entity<Buffer>,
21184        position: language::Anchor,
21185        text: &str,
21186        trigger_in_words: bool,
21187        menu_is_open: bool,
21188        cx: &mut Context<Editor>,
21189    ) -> bool {
21190        let mut chars = text.chars();
21191        let char = if let Some(char) = chars.next() {
21192            char
21193        } else {
21194            return false;
21195        };
21196        if chars.next().is_some() {
21197            return false;
21198        }
21199
21200        let buffer = buffer.read(cx);
21201        let snapshot = buffer.snapshot();
21202        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21203            return false;
21204        }
21205        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21206        if trigger_in_words && classifier.is_word(char) {
21207            return true;
21208        }
21209
21210        buffer.completion_triggers().contains(text)
21211    }
21212}
21213
21214impl SemanticsProvider for Entity<Project> {
21215    fn hover(
21216        &self,
21217        buffer: &Entity<Buffer>,
21218        position: text::Anchor,
21219        cx: &mut App,
21220    ) -> Option<Task<Vec<project::Hover>>> {
21221        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21222    }
21223
21224    fn document_highlights(
21225        &self,
21226        buffer: &Entity<Buffer>,
21227        position: text::Anchor,
21228        cx: &mut App,
21229    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21230        Some(self.update(cx, |project, cx| {
21231            project.document_highlights(buffer, position, cx)
21232        }))
21233    }
21234
21235    fn definitions(
21236        &self,
21237        buffer: &Entity<Buffer>,
21238        position: text::Anchor,
21239        kind: GotoDefinitionKind,
21240        cx: &mut App,
21241    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21242        Some(self.update(cx, |project, cx| match kind {
21243            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21244            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21245            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21246            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21247        }))
21248    }
21249
21250    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21251        // TODO: make this work for remote projects
21252        self.update(cx, |project, cx| {
21253            if project
21254                .active_debug_session(cx)
21255                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21256            {
21257                return true;
21258            }
21259
21260            buffer.update(cx, |buffer, cx| {
21261                project.any_language_server_supports_inlay_hints(buffer, cx)
21262            })
21263        })
21264    }
21265
21266    fn inline_values(
21267        &self,
21268        buffer_handle: Entity<Buffer>,
21269
21270        range: Range<text::Anchor>,
21271        cx: &mut App,
21272    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21273        self.update(cx, |project, cx| {
21274            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21275
21276            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21277        })
21278    }
21279
21280    fn inlay_hints(
21281        &self,
21282        buffer_handle: Entity<Buffer>,
21283        range: Range<text::Anchor>,
21284        cx: &mut App,
21285    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21286        Some(self.update(cx, |project, cx| {
21287            project.inlay_hints(buffer_handle, range, cx)
21288        }))
21289    }
21290
21291    fn resolve_inlay_hint(
21292        &self,
21293        hint: InlayHint,
21294        buffer_handle: Entity<Buffer>,
21295        server_id: LanguageServerId,
21296        cx: &mut App,
21297    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21298        Some(self.update(cx, |project, cx| {
21299            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21300        }))
21301    }
21302
21303    fn range_for_rename(
21304        &self,
21305        buffer: &Entity<Buffer>,
21306        position: text::Anchor,
21307        cx: &mut App,
21308    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21309        Some(self.update(cx, |project, cx| {
21310            let buffer = buffer.clone();
21311            let task = project.prepare_rename(buffer.clone(), position, cx);
21312            cx.spawn(async move |_, cx| {
21313                Ok(match task.await? {
21314                    PrepareRenameResponse::Success(range) => Some(range),
21315                    PrepareRenameResponse::InvalidPosition => None,
21316                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21317                        // Fallback on using TreeSitter info to determine identifier range
21318                        buffer.read_with(cx, |buffer, _| {
21319                            let snapshot = buffer.snapshot();
21320                            let (range, kind) = snapshot.surrounding_word(position);
21321                            if kind != Some(CharKind::Word) {
21322                                return None;
21323                            }
21324                            Some(
21325                                snapshot.anchor_before(range.start)
21326                                    ..snapshot.anchor_after(range.end),
21327                            )
21328                        })?
21329                    }
21330                })
21331            })
21332        }))
21333    }
21334
21335    fn perform_rename(
21336        &self,
21337        buffer: &Entity<Buffer>,
21338        position: text::Anchor,
21339        new_name: String,
21340        cx: &mut App,
21341    ) -> Option<Task<Result<ProjectTransaction>>> {
21342        Some(self.update(cx, |project, cx| {
21343            project.perform_rename(buffer.clone(), position, new_name, cx)
21344        }))
21345    }
21346
21347    fn pull_diagnostics_for_buffer(
21348        &self,
21349        buffer: Entity<Buffer>,
21350        cx: &mut App,
21351    ) -> Task<anyhow::Result<()>> {
21352        let diagnostics = self.update(cx, |project, cx| {
21353            project
21354                .lsp_store()
21355                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21356        });
21357        let project = self.clone();
21358        cx.spawn(async move |cx| {
21359            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21360            project.update(cx, |project, cx| {
21361                project.lsp_store().update(cx, |lsp_store, cx| {
21362                    for diagnostics_set in diagnostics {
21363                        let LspPullDiagnostics::Response {
21364                            server_id,
21365                            uri,
21366                            diagnostics,
21367                        } = diagnostics_set
21368                        else {
21369                            continue;
21370                        };
21371
21372                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21373                        let disk_based_sources = adapter
21374                            .as_ref()
21375                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21376                            .unwrap_or(&[]);
21377                        match diagnostics {
21378                            PulledDiagnostics::Unchanged { result_id } => {
21379                                lsp_store
21380                                    .merge_diagnostics(
21381                                        server_id,
21382                                        lsp::PublishDiagnosticsParams {
21383                                            uri: uri.clone(),
21384                                            diagnostics: Vec::new(),
21385                                            version: None,
21386                                        },
21387                                        Some(result_id),
21388                                        DiagnosticSourceKind::Pulled,
21389                                        disk_based_sources,
21390                                        |_, _| true,
21391                                        cx,
21392                                    )
21393                                    .log_err();
21394                            }
21395                            PulledDiagnostics::Changed {
21396                                diagnostics,
21397                                result_id,
21398                            } => {
21399                                lsp_store
21400                                    .merge_diagnostics(
21401                                        server_id,
21402                                        lsp::PublishDiagnosticsParams {
21403                                            uri: uri.clone(),
21404                                            diagnostics,
21405                                            version: None,
21406                                        },
21407                                        result_id,
21408                                        DiagnosticSourceKind::Pulled,
21409                                        disk_based_sources,
21410                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21411                                            DiagnosticSourceKind::Pulled => false,
21412                                            DiagnosticSourceKind::Other
21413                                            | DiagnosticSourceKind::Pushed => true,
21414                                        },
21415                                        cx,
21416                                    )
21417                                    .log_err();
21418                            }
21419                        }
21420                    }
21421                })
21422            })
21423        })
21424    }
21425}
21426
21427fn inlay_hint_settings(
21428    location: Anchor,
21429    snapshot: &MultiBufferSnapshot,
21430    cx: &mut Context<Editor>,
21431) -> InlayHintSettings {
21432    let file = snapshot.file_at(location);
21433    let language = snapshot.language_at(location).map(|l| l.name());
21434    language_settings(language, file, cx).inlay_hints
21435}
21436
21437fn consume_contiguous_rows(
21438    contiguous_row_selections: &mut Vec<Selection<Point>>,
21439    selection: &Selection<Point>,
21440    display_map: &DisplaySnapshot,
21441    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21442) -> (MultiBufferRow, MultiBufferRow) {
21443    contiguous_row_selections.push(selection.clone());
21444    let start_row = MultiBufferRow(selection.start.row);
21445    let mut end_row = ending_row(selection, display_map);
21446
21447    while let Some(next_selection) = selections.peek() {
21448        if next_selection.start.row <= end_row.0 {
21449            end_row = ending_row(next_selection, display_map);
21450            contiguous_row_selections.push(selections.next().unwrap().clone());
21451        } else {
21452            break;
21453        }
21454    }
21455    (start_row, end_row)
21456}
21457
21458fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21459    if next_selection.end.column > 0 || next_selection.is_empty() {
21460        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21461    } else {
21462        MultiBufferRow(next_selection.end.row)
21463    }
21464}
21465
21466impl EditorSnapshot {
21467    pub fn remote_selections_in_range<'a>(
21468        &'a self,
21469        range: &'a Range<Anchor>,
21470        collaboration_hub: &dyn CollaborationHub,
21471        cx: &'a App,
21472    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21473        let participant_names = collaboration_hub.user_names(cx);
21474        let participant_indices = collaboration_hub.user_participant_indices(cx);
21475        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21476        let collaborators_by_replica_id = collaborators_by_peer_id
21477            .values()
21478            .map(|collaborator| (collaborator.replica_id, collaborator))
21479            .collect::<HashMap<_, _>>();
21480        self.buffer_snapshot
21481            .selections_in_range(range, false)
21482            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21483                if replica_id == AGENT_REPLICA_ID {
21484                    Some(RemoteSelection {
21485                        replica_id,
21486                        selection,
21487                        cursor_shape,
21488                        line_mode,
21489                        collaborator_id: CollaboratorId::Agent,
21490                        user_name: Some("Agent".into()),
21491                        color: cx.theme().players().agent(),
21492                    })
21493                } else {
21494                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21495                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21496                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21497                    Some(RemoteSelection {
21498                        replica_id,
21499                        selection,
21500                        cursor_shape,
21501                        line_mode,
21502                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21503                        user_name,
21504                        color: if let Some(index) = participant_index {
21505                            cx.theme().players().color_for_participant(index.0)
21506                        } else {
21507                            cx.theme().players().absent()
21508                        },
21509                    })
21510                }
21511            })
21512    }
21513
21514    pub fn hunks_for_ranges(
21515        &self,
21516        ranges: impl IntoIterator<Item = Range<Point>>,
21517    ) -> Vec<MultiBufferDiffHunk> {
21518        let mut hunks = Vec::new();
21519        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21520            HashMap::default();
21521        for query_range in ranges {
21522            let query_rows =
21523                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21524            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21525                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21526            ) {
21527                // Include deleted hunks that are adjacent to the query range, because
21528                // otherwise they would be missed.
21529                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21530                if hunk.status().is_deleted() {
21531                    intersects_range |= hunk.row_range.start == query_rows.end;
21532                    intersects_range |= hunk.row_range.end == query_rows.start;
21533                }
21534                if intersects_range {
21535                    if !processed_buffer_rows
21536                        .entry(hunk.buffer_id)
21537                        .or_default()
21538                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21539                    {
21540                        continue;
21541                    }
21542                    hunks.push(hunk);
21543                }
21544            }
21545        }
21546
21547        hunks
21548    }
21549
21550    fn display_diff_hunks_for_rows<'a>(
21551        &'a self,
21552        display_rows: Range<DisplayRow>,
21553        folded_buffers: &'a HashSet<BufferId>,
21554    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21555        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21556        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21557
21558        self.buffer_snapshot
21559            .diff_hunks_in_range(buffer_start..buffer_end)
21560            .filter_map(|hunk| {
21561                if folded_buffers.contains(&hunk.buffer_id) {
21562                    return None;
21563                }
21564
21565                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21566                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21567
21568                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21569                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21570
21571                let display_hunk = if hunk_display_start.column() != 0 {
21572                    DisplayDiffHunk::Folded {
21573                        display_row: hunk_display_start.row(),
21574                    }
21575                } else {
21576                    let mut end_row = hunk_display_end.row();
21577                    if hunk_display_end.column() > 0 {
21578                        end_row.0 += 1;
21579                    }
21580                    let is_created_file = hunk.is_created_file();
21581                    DisplayDiffHunk::Unfolded {
21582                        status: hunk.status(),
21583                        diff_base_byte_range: hunk.diff_base_byte_range,
21584                        display_row_range: hunk_display_start.row()..end_row,
21585                        multi_buffer_range: Anchor::range_in_buffer(
21586                            hunk.excerpt_id,
21587                            hunk.buffer_id,
21588                            hunk.buffer_range,
21589                        ),
21590                        is_created_file,
21591                    }
21592                };
21593
21594                Some(display_hunk)
21595            })
21596    }
21597
21598    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21599        self.display_snapshot.buffer_snapshot.language_at(position)
21600    }
21601
21602    pub fn is_focused(&self) -> bool {
21603        self.is_focused
21604    }
21605
21606    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21607        self.placeholder_text.as_ref()
21608    }
21609
21610    pub fn scroll_position(&self) -> gpui::Point<f32> {
21611        self.scroll_anchor.scroll_position(&self.display_snapshot)
21612    }
21613
21614    fn gutter_dimensions(
21615        &self,
21616        font_id: FontId,
21617        font_size: Pixels,
21618        max_line_number_width: Pixels,
21619        cx: &App,
21620    ) -> Option<GutterDimensions> {
21621        if !self.show_gutter {
21622            return None;
21623        }
21624
21625        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21626        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21627
21628        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21629            matches!(
21630                ProjectSettings::get_global(cx).git.git_gutter,
21631                Some(GitGutterSetting::TrackedFiles)
21632            )
21633        });
21634        let gutter_settings = EditorSettings::get_global(cx).gutter;
21635        let show_line_numbers = self
21636            .show_line_numbers
21637            .unwrap_or(gutter_settings.line_numbers);
21638        let line_gutter_width = if show_line_numbers {
21639            // Avoid flicker-like gutter resizes when the line number gains another digit by
21640            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21641            let min_width_for_number_on_gutter =
21642                ch_advance * gutter_settings.min_line_number_digits as f32;
21643            max_line_number_width.max(min_width_for_number_on_gutter)
21644        } else {
21645            0.0.into()
21646        };
21647
21648        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21649        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21650
21651        let git_blame_entries_width =
21652            self.git_blame_gutter_max_author_length
21653                .map(|max_author_length| {
21654                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21655                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21656
21657                    /// The number of characters to dedicate to gaps and margins.
21658                    const SPACING_WIDTH: usize = 4;
21659
21660                    let max_char_count = max_author_length.min(renderer.max_author_length())
21661                        + ::git::SHORT_SHA_LENGTH
21662                        + MAX_RELATIVE_TIMESTAMP.len()
21663                        + SPACING_WIDTH;
21664
21665                    ch_advance * max_char_count
21666                });
21667
21668        let is_singleton = self.buffer_snapshot.is_singleton();
21669
21670        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21671        left_padding += if !is_singleton {
21672            ch_width * 4.0
21673        } else if show_runnables || show_breakpoints {
21674            ch_width * 3.0
21675        } else if show_git_gutter && show_line_numbers {
21676            ch_width * 2.0
21677        } else if show_git_gutter || show_line_numbers {
21678            ch_width
21679        } else {
21680            px(0.)
21681        };
21682
21683        let shows_folds = is_singleton && gutter_settings.folds;
21684
21685        let right_padding = if shows_folds && show_line_numbers {
21686            ch_width * 4.0
21687        } else if shows_folds || (!is_singleton && show_line_numbers) {
21688            ch_width * 3.0
21689        } else if show_line_numbers {
21690            ch_width
21691        } else {
21692            px(0.)
21693        };
21694
21695        Some(GutterDimensions {
21696            left_padding,
21697            right_padding,
21698            width: line_gutter_width + left_padding + right_padding,
21699            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21700            git_blame_entries_width,
21701        })
21702    }
21703
21704    pub fn render_crease_toggle(
21705        &self,
21706        buffer_row: MultiBufferRow,
21707        row_contains_cursor: bool,
21708        editor: Entity<Editor>,
21709        window: &mut Window,
21710        cx: &mut App,
21711    ) -> Option<AnyElement> {
21712        let folded = self.is_line_folded(buffer_row);
21713        let mut is_foldable = false;
21714
21715        if let Some(crease) = self
21716            .crease_snapshot
21717            .query_row(buffer_row, &self.buffer_snapshot)
21718        {
21719            is_foldable = true;
21720            match crease {
21721                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21722                    if let Some(render_toggle) = render_toggle {
21723                        let toggle_callback =
21724                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21725                                if folded {
21726                                    editor.update(cx, |editor, cx| {
21727                                        editor.fold_at(buffer_row, window, cx)
21728                                    });
21729                                } else {
21730                                    editor.update(cx, |editor, cx| {
21731                                        editor.unfold_at(buffer_row, window, cx)
21732                                    });
21733                                }
21734                            });
21735                        return Some((render_toggle)(
21736                            buffer_row,
21737                            folded,
21738                            toggle_callback,
21739                            window,
21740                            cx,
21741                        ));
21742                    }
21743                }
21744            }
21745        }
21746
21747        is_foldable |= self.starts_indent(buffer_row);
21748
21749        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21750            Some(
21751                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21752                    .toggle_state(folded)
21753                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21754                        if folded {
21755                            this.unfold_at(buffer_row, window, cx);
21756                        } else {
21757                            this.fold_at(buffer_row, window, cx);
21758                        }
21759                    }))
21760                    .into_any_element(),
21761            )
21762        } else {
21763            None
21764        }
21765    }
21766
21767    pub fn render_crease_trailer(
21768        &self,
21769        buffer_row: MultiBufferRow,
21770        window: &mut Window,
21771        cx: &mut App,
21772    ) -> Option<AnyElement> {
21773        let folded = self.is_line_folded(buffer_row);
21774        if let Crease::Inline { render_trailer, .. } = self
21775            .crease_snapshot
21776            .query_row(buffer_row, &self.buffer_snapshot)?
21777        {
21778            let render_trailer = render_trailer.as_ref()?;
21779            Some(render_trailer(buffer_row, folded, window, cx))
21780        } else {
21781            None
21782        }
21783    }
21784}
21785
21786impl Deref for EditorSnapshot {
21787    type Target = DisplaySnapshot;
21788
21789    fn deref(&self) -> &Self::Target {
21790        &self.display_snapshot
21791    }
21792}
21793
21794#[derive(Clone, Debug, PartialEq, Eq)]
21795pub enum EditorEvent {
21796    InputIgnored {
21797        text: Arc<str>,
21798    },
21799    InputHandled {
21800        utf16_range_to_replace: Option<Range<isize>>,
21801        text: Arc<str>,
21802    },
21803    ExcerptsAdded {
21804        buffer: Entity<Buffer>,
21805        predecessor: ExcerptId,
21806        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21807    },
21808    ExcerptsRemoved {
21809        ids: Vec<ExcerptId>,
21810        removed_buffer_ids: Vec<BufferId>,
21811    },
21812    BufferFoldToggled {
21813        ids: Vec<ExcerptId>,
21814        folded: bool,
21815    },
21816    ExcerptsEdited {
21817        ids: Vec<ExcerptId>,
21818    },
21819    ExcerptsExpanded {
21820        ids: Vec<ExcerptId>,
21821    },
21822    BufferEdited,
21823    Edited {
21824        transaction_id: clock::Lamport,
21825    },
21826    Reparsed(BufferId),
21827    Focused,
21828    FocusedIn,
21829    Blurred,
21830    DirtyChanged,
21831    Saved,
21832    TitleChanged,
21833    DiffBaseChanged,
21834    SelectionsChanged {
21835        local: bool,
21836    },
21837    ScrollPositionChanged {
21838        local: bool,
21839        autoscroll: bool,
21840    },
21841    Closed,
21842    TransactionUndone {
21843        transaction_id: clock::Lamport,
21844    },
21845    TransactionBegun {
21846        transaction_id: clock::Lamport,
21847    },
21848    Reloaded,
21849    CursorShapeChanged,
21850    PushedToNavHistory {
21851        anchor: Anchor,
21852        is_deactivate: bool,
21853    },
21854}
21855
21856impl EventEmitter<EditorEvent> for Editor {}
21857
21858impl Focusable for Editor {
21859    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21860        self.focus_handle.clone()
21861    }
21862}
21863
21864impl Render for Editor {
21865    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21866        let settings = ThemeSettings::get_global(cx);
21867
21868        let mut text_style = match self.mode {
21869            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21870                color: cx.theme().colors().editor_foreground,
21871                font_family: settings.ui_font.family.clone(),
21872                font_features: settings.ui_font.features.clone(),
21873                font_fallbacks: settings.ui_font.fallbacks.clone(),
21874                font_size: rems(0.875).into(),
21875                font_weight: settings.ui_font.weight,
21876                line_height: relative(settings.buffer_line_height.value()),
21877                ..Default::default()
21878            },
21879            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21880                color: cx.theme().colors().editor_foreground,
21881                font_family: settings.buffer_font.family.clone(),
21882                font_features: settings.buffer_font.features.clone(),
21883                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21884                font_size: settings.buffer_font_size(cx).into(),
21885                font_weight: settings.buffer_font.weight,
21886                line_height: relative(settings.buffer_line_height.value()),
21887                ..Default::default()
21888            },
21889        };
21890        if let Some(text_style_refinement) = &self.text_style_refinement {
21891            text_style.refine(text_style_refinement)
21892        }
21893
21894        let background = match self.mode {
21895            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21896            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
21897            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21898            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21899        };
21900
21901        EditorElement::new(
21902            &cx.entity(),
21903            EditorStyle {
21904                background,
21905                local_player: cx.theme().players().local(),
21906                text: text_style,
21907                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21908                syntax: cx.theme().syntax().clone(),
21909                status: cx.theme().status().clone(),
21910                inlay_hints_style: make_inlay_hints_style(cx),
21911                inline_completion_styles: make_suggestion_styles(cx),
21912                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21913                show_underlines: !self.mode.is_minimap(),
21914            },
21915        )
21916    }
21917}
21918
21919impl EntityInputHandler for Editor {
21920    fn text_for_range(
21921        &mut self,
21922        range_utf16: Range<usize>,
21923        adjusted_range: &mut Option<Range<usize>>,
21924        _: &mut Window,
21925        cx: &mut Context<Self>,
21926    ) -> Option<String> {
21927        let snapshot = self.buffer.read(cx).read(cx);
21928        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21929        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21930        if (start.0..end.0) != range_utf16 {
21931            adjusted_range.replace(start.0..end.0);
21932        }
21933        Some(snapshot.text_for_range(start..end).collect())
21934    }
21935
21936    fn selected_text_range(
21937        &mut self,
21938        ignore_disabled_input: bool,
21939        _: &mut Window,
21940        cx: &mut Context<Self>,
21941    ) -> Option<UTF16Selection> {
21942        // Prevent the IME menu from appearing when holding down an alphabetic key
21943        // while input is disabled.
21944        if !ignore_disabled_input && !self.input_enabled {
21945            return None;
21946        }
21947
21948        let selection = self.selections.newest::<OffsetUtf16>(cx);
21949        let range = selection.range();
21950
21951        Some(UTF16Selection {
21952            range: range.start.0..range.end.0,
21953            reversed: selection.reversed,
21954        })
21955    }
21956
21957    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21958        let snapshot = self.buffer.read(cx).read(cx);
21959        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21960        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21961    }
21962
21963    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21964        self.clear_highlights::<InputComposition>(cx);
21965        self.ime_transaction.take();
21966    }
21967
21968    fn replace_text_in_range(
21969        &mut self,
21970        range_utf16: Option<Range<usize>>,
21971        text: &str,
21972        window: &mut Window,
21973        cx: &mut Context<Self>,
21974    ) {
21975        if !self.input_enabled {
21976            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21977            return;
21978        }
21979
21980        self.transact(window, cx, |this, window, cx| {
21981            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21982                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21983                Some(this.selection_replacement_ranges(range_utf16, cx))
21984            } else {
21985                this.marked_text_ranges(cx)
21986            };
21987
21988            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21989                let newest_selection_id = this.selections.newest_anchor().id;
21990                this.selections
21991                    .all::<OffsetUtf16>(cx)
21992                    .iter()
21993                    .zip(ranges_to_replace.iter())
21994                    .find_map(|(selection, range)| {
21995                        if selection.id == newest_selection_id {
21996                            Some(
21997                                (range.start.0 as isize - selection.head().0 as isize)
21998                                    ..(range.end.0 as isize - selection.head().0 as isize),
21999                            )
22000                        } else {
22001                            None
22002                        }
22003                    })
22004            });
22005
22006            cx.emit(EditorEvent::InputHandled {
22007                utf16_range_to_replace: range_to_replace,
22008                text: text.into(),
22009            });
22010
22011            if let Some(new_selected_ranges) = new_selected_ranges {
22012                this.change_selections(None, window, cx, |selections| {
22013                    selections.select_ranges(new_selected_ranges)
22014                });
22015                this.backspace(&Default::default(), window, cx);
22016            }
22017
22018            this.handle_input(text, window, cx);
22019        });
22020
22021        if let Some(transaction) = self.ime_transaction {
22022            self.buffer.update(cx, |buffer, cx| {
22023                buffer.group_until_transaction(transaction, cx);
22024            });
22025        }
22026
22027        self.unmark_text(window, cx);
22028    }
22029
22030    fn replace_and_mark_text_in_range(
22031        &mut self,
22032        range_utf16: Option<Range<usize>>,
22033        text: &str,
22034        new_selected_range_utf16: Option<Range<usize>>,
22035        window: &mut Window,
22036        cx: &mut Context<Self>,
22037    ) {
22038        if !self.input_enabled {
22039            return;
22040        }
22041
22042        let transaction = self.transact(window, cx, |this, window, cx| {
22043            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22044                let snapshot = this.buffer.read(cx).read(cx);
22045                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22046                    for marked_range in &mut marked_ranges {
22047                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22048                        marked_range.start.0 += relative_range_utf16.start;
22049                        marked_range.start =
22050                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22051                        marked_range.end =
22052                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22053                    }
22054                }
22055                Some(marked_ranges)
22056            } else if let Some(range_utf16) = range_utf16 {
22057                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22058                Some(this.selection_replacement_ranges(range_utf16, cx))
22059            } else {
22060                None
22061            };
22062
22063            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22064                let newest_selection_id = this.selections.newest_anchor().id;
22065                this.selections
22066                    .all::<OffsetUtf16>(cx)
22067                    .iter()
22068                    .zip(ranges_to_replace.iter())
22069                    .find_map(|(selection, range)| {
22070                        if selection.id == newest_selection_id {
22071                            Some(
22072                                (range.start.0 as isize - selection.head().0 as isize)
22073                                    ..(range.end.0 as isize - selection.head().0 as isize),
22074                            )
22075                        } else {
22076                            None
22077                        }
22078                    })
22079            });
22080
22081            cx.emit(EditorEvent::InputHandled {
22082                utf16_range_to_replace: range_to_replace,
22083                text: text.into(),
22084            });
22085
22086            if let Some(ranges) = ranges_to_replace {
22087                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22088            }
22089
22090            let marked_ranges = {
22091                let snapshot = this.buffer.read(cx).read(cx);
22092                this.selections
22093                    .disjoint_anchors()
22094                    .iter()
22095                    .map(|selection| {
22096                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22097                    })
22098                    .collect::<Vec<_>>()
22099            };
22100
22101            if text.is_empty() {
22102                this.unmark_text(window, cx);
22103            } else {
22104                this.highlight_text::<InputComposition>(
22105                    marked_ranges.clone(),
22106                    HighlightStyle {
22107                        underline: Some(UnderlineStyle {
22108                            thickness: px(1.),
22109                            color: None,
22110                            wavy: false,
22111                        }),
22112                        ..Default::default()
22113                    },
22114                    cx,
22115                );
22116            }
22117
22118            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22119            let use_autoclose = this.use_autoclose;
22120            let use_auto_surround = this.use_auto_surround;
22121            this.set_use_autoclose(false);
22122            this.set_use_auto_surround(false);
22123            this.handle_input(text, window, cx);
22124            this.set_use_autoclose(use_autoclose);
22125            this.set_use_auto_surround(use_auto_surround);
22126
22127            if let Some(new_selected_range) = new_selected_range_utf16 {
22128                let snapshot = this.buffer.read(cx).read(cx);
22129                let new_selected_ranges = marked_ranges
22130                    .into_iter()
22131                    .map(|marked_range| {
22132                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22133                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22134                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22135                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22136                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22137                    })
22138                    .collect::<Vec<_>>();
22139
22140                drop(snapshot);
22141                this.change_selections(None, window, cx, |selections| {
22142                    selections.select_ranges(new_selected_ranges)
22143                });
22144            }
22145        });
22146
22147        self.ime_transaction = self.ime_transaction.or(transaction);
22148        if let Some(transaction) = self.ime_transaction {
22149            self.buffer.update(cx, |buffer, cx| {
22150                buffer.group_until_transaction(transaction, cx);
22151            });
22152        }
22153
22154        if self.text_highlights::<InputComposition>(cx).is_none() {
22155            self.ime_transaction.take();
22156        }
22157    }
22158
22159    fn bounds_for_range(
22160        &mut self,
22161        range_utf16: Range<usize>,
22162        element_bounds: gpui::Bounds<Pixels>,
22163        window: &mut Window,
22164        cx: &mut Context<Self>,
22165    ) -> Option<gpui::Bounds<Pixels>> {
22166        let text_layout_details = self.text_layout_details(window);
22167        let gpui::Size {
22168            width: em_width,
22169            height: line_height,
22170        } = self.character_size(window);
22171
22172        let snapshot = self.snapshot(window, cx);
22173        let scroll_position = snapshot.scroll_position();
22174        let scroll_left = scroll_position.x * em_width;
22175
22176        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22177        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22178            + self.gutter_dimensions.width
22179            + self.gutter_dimensions.margin;
22180        let y = line_height * (start.row().as_f32() - scroll_position.y);
22181
22182        Some(Bounds {
22183            origin: element_bounds.origin + point(x, y),
22184            size: size(em_width, line_height),
22185        })
22186    }
22187
22188    fn character_index_for_point(
22189        &mut self,
22190        point: gpui::Point<Pixels>,
22191        _window: &mut Window,
22192        _cx: &mut Context<Self>,
22193    ) -> Option<usize> {
22194        let position_map = self.last_position_map.as_ref()?;
22195        if !position_map.text_hitbox.contains(&point) {
22196            return None;
22197        }
22198        let display_point = position_map.point_for_position(point).previous_valid;
22199        let anchor = position_map
22200            .snapshot
22201            .display_point_to_anchor(display_point, Bias::Left);
22202        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22203        Some(utf16_offset.0)
22204    }
22205}
22206
22207trait SelectionExt {
22208    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22209    fn spanned_rows(
22210        &self,
22211        include_end_if_at_line_start: bool,
22212        map: &DisplaySnapshot,
22213    ) -> Range<MultiBufferRow>;
22214}
22215
22216impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22217    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22218        let start = self
22219            .start
22220            .to_point(&map.buffer_snapshot)
22221            .to_display_point(map);
22222        let end = self
22223            .end
22224            .to_point(&map.buffer_snapshot)
22225            .to_display_point(map);
22226        if self.reversed {
22227            end..start
22228        } else {
22229            start..end
22230        }
22231    }
22232
22233    fn spanned_rows(
22234        &self,
22235        include_end_if_at_line_start: bool,
22236        map: &DisplaySnapshot,
22237    ) -> Range<MultiBufferRow> {
22238        let start = self.start.to_point(&map.buffer_snapshot);
22239        let mut end = self.end.to_point(&map.buffer_snapshot);
22240        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22241            end.row -= 1;
22242        }
22243
22244        let buffer_start = map.prev_line_boundary(start).0;
22245        let buffer_end = map.next_line_boundary(end).0;
22246        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22247    }
22248}
22249
22250impl<T: InvalidationRegion> InvalidationStack<T> {
22251    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22252    where
22253        S: Clone + ToOffset,
22254    {
22255        while let Some(region) = self.last() {
22256            let all_selections_inside_invalidation_ranges =
22257                if selections.len() == region.ranges().len() {
22258                    selections
22259                        .iter()
22260                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22261                        .all(|(selection, invalidation_range)| {
22262                            let head = selection.head().to_offset(buffer);
22263                            invalidation_range.start <= head && invalidation_range.end >= head
22264                        })
22265                } else {
22266                    false
22267                };
22268
22269            if all_selections_inside_invalidation_ranges {
22270                break;
22271            } else {
22272                self.pop();
22273            }
22274        }
22275    }
22276}
22277
22278impl<T> Default for InvalidationStack<T> {
22279    fn default() -> Self {
22280        Self(Default::default())
22281    }
22282}
22283
22284impl<T> Deref for InvalidationStack<T> {
22285    type Target = Vec<T>;
22286
22287    fn deref(&self) -> &Self::Target {
22288        &self.0
22289    }
22290}
22291
22292impl<T> DerefMut for InvalidationStack<T> {
22293    fn deref_mut(&mut self) -> &mut Self::Target {
22294        &mut self.0
22295    }
22296}
22297
22298impl InvalidationRegion for SnippetState {
22299    fn ranges(&self) -> &[Range<Anchor>] {
22300        &self.ranges[self.active_index]
22301    }
22302}
22303
22304fn inline_completion_edit_text(
22305    current_snapshot: &BufferSnapshot,
22306    edits: &[(Range<Anchor>, String)],
22307    edit_preview: &EditPreview,
22308    include_deletions: bool,
22309    cx: &App,
22310) -> HighlightedText {
22311    let edits = edits
22312        .iter()
22313        .map(|(anchor, text)| {
22314            (
22315                anchor.start.text_anchor..anchor.end.text_anchor,
22316                text.clone(),
22317            )
22318        })
22319        .collect::<Vec<_>>();
22320
22321    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22322}
22323
22324pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22325    match severity {
22326        lsp::DiagnosticSeverity::ERROR => colors.error,
22327        lsp::DiagnosticSeverity::WARNING => colors.warning,
22328        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22329        lsp::DiagnosticSeverity::HINT => colors.info,
22330        _ => colors.ignored,
22331    }
22332}
22333
22334pub fn styled_runs_for_code_label<'a>(
22335    label: &'a CodeLabel,
22336    syntax_theme: &'a theme::SyntaxTheme,
22337) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22338    let fade_out = HighlightStyle {
22339        fade_out: Some(0.35),
22340        ..Default::default()
22341    };
22342
22343    let mut prev_end = label.filter_range.end;
22344    label
22345        .runs
22346        .iter()
22347        .enumerate()
22348        .flat_map(move |(ix, (range, highlight_id))| {
22349            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22350                style
22351            } else {
22352                return Default::default();
22353            };
22354            let mut muted_style = style;
22355            muted_style.highlight(fade_out);
22356
22357            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22358            if range.start >= label.filter_range.end {
22359                if range.start > prev_end {
22360                    runs.push((prev_end..range.start, fade_out));
22361                }
22362                runs.push((range.clone(), muted_style));
22363            } else if range.end <= label.filter_range.end {
22364                runs.push((range.clone(), style));
22365            } else {
22366                runs.push((range.start..label.filter_range.end, style));
22367                runs.push((label.filter_range.end..range.end, muted_style));
22368            }
22369            prev_end = cmp::max(prev_end, range.end);
22370
22371            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22372                runs.push((prev_end..label.text.len(), fade_out));
22373            }
22374
22375            runs
22376        })
22377}
22378
22379pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22380    let mut prev_index = 0;
22381    let mut prev_codepoint: Option<char> = None;
22382    text.char_indices()
22383        .chain([(text.len(), '\0')])
22384        .filter_map(move |(index, codepoint)| {
22385            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22386            let is_boundary = index == text.len()
22387                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22388                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22389            if is_boundary {
22390                let chunk = &text[prev_index..index];
22391                prev_index = index;
22392                Some(chunk)
22393            } else {
22394                None
22395            }
22396        })
22397}
22398
22399pub trait RangeToAnchorExt: Sized {
22400    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22401
22402    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22403        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22404        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22405    }
22406}
22407
22408impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22409    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22410        let start_offset = self.start.to_offset(snapshot);
22411        let end_offset = self.end.to_offset(snapshot);
22412        if start_offset == end_offset {
22413            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22414        } else {
22415            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22416        }
22417    }
22418}
22419
22420pub trait RowExt {
22421    fn as_f32(&self) -> f32;
22422
22423    fn next_row(&self) -> Self;
22424
22425    fn previous_row(&self) -> Self;
22426
22427    fn minus(&self, other: Self) -> u32;
22428}
22429
22430impl RowExt for DisplayRow {
22431    fn as_f32(&self) -> f32 {
22432        self.0 as f32
22433    }
22434
22435    fn next_row(&self) -> Self {
22436        Self(self.0 + 1)
22437    }
22438
22439    fn previous_row(&self) -> Self {
22440        Self(self.0.saturating_sub(1))
22441    }
22442
22443    fn minus(&self, other: Self) -> u32 {
22444        self.0 - other.0
22445    }
22446}
22447
22448impl RowExt for MultiBufferRow {
22449    fn as_f32(&self) -> f32 {
22450        self.0 as f32
22451    }
22452
22453    fn next_row(&self) -> Self {
22454        Self(self.0 + 1)
22455    }
22456
22457    fn previous_row(&self) -> Self {
22458        Self(self.0.saturating_sub(1))
22459    }
22460
22461    fn minus(&self, other: Self) -> u32 {
22462        self.0 - other.0
22463    }
22464}
22465
22466trait RowRangeExt {
22467    type Row;
22468
22469    fn len(&self) -> usize;
22470
22471    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22472}
22473
22474impl RowRangeExt for Range<MultiBufferRow> {
22475    type Row = MultiBufferRow;
22476
22477    fn len(&self) -> usize {
22478        (self.end.0 - self.start.0) as usize
22479    }
22480
22481    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22482        (self.start.0..self.end.0).map(MultiBufferRow)
22483    }
22484}
22485
22486impl RowRangeExt for Range<DisplayRow> {
22487    type Row = DisplayRow;
22488
22489    fn len(&self) -> usize {
22490        (self.end.0 - self.start.0) as usize
22491    }
22492
22493    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22494        (self.start.0..self.end.0).map(DisplayRow)
22495    }
22496}
22497
22498/// If select range has more than one line, we
22499/// just point the cursor to range.start.
22500fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22501    if range.start.row == range.end.row {
22502        range
22503    } else {
22504        range.start..range.start
22505    }
22506}
22507pub struct KillRing(ClipboardItem);
22508impl Global for KillRing {}
22509
22510const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22511
22512enum BreakpointPromptEditAction {
22513    Log,
22514    Condition,
22515    HitCondition,
22516}
22517
22518struct BreakpointPromptEditor {
22519    pub(crate) prompt: Entity<Editor>,
22520    editor: WeakEntity<Editor>,
22521    breakpoint_anchor: Anchor,
22522    breakpoint: Breakpoint,
22523    edit_action: BreakpointPromptEditAction,
22524    block_ids: HashSet<CustomBlockId>,
22525    editor_margins: Arc<Mutex<EditorMargins>>,
22526    _subscriptions: Vec<Subscription>,
22527}
22528
22529impl BreakpointPromptEditor {
22530    const MAX_LINES: u8 = 4;
22531
22532    fn new(
22533        editor: WeakEntity<Editor>,
22534        breakpoint_anchor: Anchor,
22535        breakpoint: Breakpoint,
22536        edit_action: BreakpointPromptEditAction,
22537        window: &mut Window,
22538        cx: &mut Context<Self>,
22539    ) -> Self {
22540        let base_text = match edit_action {
22541            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22542            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22543            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22544        }
22545        .map(|msg| msg.to_string())
22546        .unwrap_or_default();
22547
22548        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22549        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22550
22551        let prompt = cx.new(|cx| {
22552            let mut prompt = Editor::new(
22553                EditorMode::AutoHeight {
22554                    min_lines: 1,
22555                    max_lines: Self::MAX_LINES as usize,
22556                },
22557                buffer,
22558                None,
22559                window,
22560                cx,
22561            );
22562            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22563            prompt.set_show_cursor_when_unfocused(false, cx);
22564            prompt.set_placeholder_text(
22565                match edit_action {
22566                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22567                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22568                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22569                },
22570                cx,
22571            );
22572
22573            prompt
22574        });
22575
22576        Self {
22577            prompt,
22578            editor,
22579            breakpoint_anchor,
22580            breakpoint,
22581            edit_action,
22582            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22583            block_ids: Default::default(),
22584            _subscriptions: vec![],
22585        }
22586    }
22587
22588    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22589        self.block_ids.extend(block_ids)
22590    }
22591
22592    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22593        if let Some(editor) = self.editor.upgrade() {
22594            let message = self
22595                .prompt
22596                .read(cx)
22597                .buffer
22598                .read(cx)
22599                .as_singleton()
22600                .expect("A multi buffer in breakpoint prompt isn't possible")
22601                .read(cx)
22602                .as_rope()
22603                .to_string();
22604
22605            editor.update(cx, |editor, cx| {
22606                editor.edit_breakpoint_at_anchor(
22607                    self.breakpoint_anchor,
22608                    self.breakpoint.clone(),
22609                    match self.edit_action {
22610                        BreakpointPromptEditAction::Log => {
22611                            BreakpointEditAction::EditLogMessage(message.into())
22612                        }
22613                        BreakpointPromptEditAction::Condition => {
22614                            BreakpointEditAction::EditCondition(message.into())
22615                        }
22616                        BreakpointPromptEditAction::HitCondition => {
22617                            BreakpointEditAction::EditHitCondition(message.into())
22618                        }
22619                    },
22620                    cx,
22621                );
22622
22623                editor.remove_blocks(self.block_ids.clone(), None, cx);
22624                cx.focus_self(window);
22625            });
22626        }
22627    }
22628
22629    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22630        self.editor
22631            .update(cx, |editor, cx| {
22632                editor.remove_blocks(self.block_ids.clone(), None, cx);
22633                window.focus(&editor.focus_handle);
22634            })
22635            .log_err();
22636    }
22637
22638    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22639        let settings = ThemeSettings::get_global(cx);
22640        let text_style = TextStyle {
22641            color: if self.prompt.read(cx).read_only(cx) {
22642                cx.theme().colors().text_disabled
22643            } else {
22644                cx.theme().colors().text
22645            },
22646            font_family: settings.buffer_font.family.clone(),
22647            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22648            font_size: settings.buffer_font_size(cx).into(),
22649            font_weight: settings.buffer_font.weight,
22650            line_height: relative(settings.buffer_line_height.value()),
22651            ..Default::default()
22652        };
22653        EditorElement::new(
22654            &self.prompt,
22655            EditorStyle {
22656                background: cx.theme().colors().editor_background,
22657                local_player: cx.theme().players().local(),
22658                text: text_style,
22659                ..Default::default()
22660            },
22661        )
22662    }
22663}
22664
22665impl Render for BreakpointPromptEditor {
22666    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22667        let editor_margins = *self.editor_margins.lock();
22668        let gutter_dimensions = editor_margins.gutter;
22669        h_flex()
22670            .key_context("Editor")
22671            .bg(cx.theme().colors().editor_background)
22672            .border_y_1()
22673            .border_color(cx.theme().status().info_border)
22674            .size_full()
22675            .py(window.line_height() / 2.5)
22676            .on_action(cx.listener(Self::confirm))
22677            .on_action(cx.listener(Self::cancel))
22678            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22679            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22680    }
22681}
22682
22683impl Focusable for BreakpointPromptEditor {
22684    fn focus_handle(&self, cx: &App) -> FocusHandle {
22685        self.prompt.focus_handle(cx)
22686    }
22687}
22688
22689fn all_edits_insertions_or_deletions(
22690    edits: &Vec<(Range<Anchor>, String)>,
22691    snapshot: &MultiBufferSnapshot,
22692) -> bool {
22693    let mut all_insertions = true;
22694    let mut all_deletions = true;
22695
22696    for (range, new_text) in edits.iter() {
22697        let range_is_empty = range.to_offset(&snapshot).is_empty();
22698        let text_is_empty = new_text.is_empty();
22699
22700        if range_is_empty != text_is_empty {
22701            if range_is_empty {
22702                all_deletions = false;
22703            } else {
22704                all_insertions = false;
22705            }
22706        } else {
22707            return false;
22708        }
22709
22710        if !all_insertions && !all_deletions {
22711            return false;
22712        }
22713    }
22714    all_insertions || all_deletions
22715}
22716
22717struct MissingEditPredictionKeybindingTooltip;
22718
22719impl Render for MissingEditPredictionKeybindingTooltip {
22720    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22721        ui::tooltip_container(window, cx, |container, _, cx| {
22722            container
22723                .flex_shrink_0()
22724                .max_w_80()
22725                .min_h(rems_from_px(124.))
22726                .justify_between()
22727                .child(
22728                    v_flex()
22729                        .flex_1()
22730                        .text_ui_sm(cx)
22731                        .child(Label::new("Conflict with Accept Keybinding"))
22732                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22733                )
22734                .child(
22735                    h_flex()
22736                        .pb_1()
22737                        .gap_1()
22738                        .items_end()
22739                        .w_full()
22740                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22741                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22742                        }))
22743                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22744                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22745                        })),
22746                )
22747        })
22748    }
22749}
22750
22751#[derive(Debug, Clone, Copy, PartialEq)]
22752pub struct LineHighlight {
22753    pub background: Background,
22754    pub border: Option<gpui::Hsla>,
22755    pub include_gutter: bool,
22756    pub type_id: Option<TypeId>,
22757}
22758
22759fn render_diff_hunk_controls(
22760    row: u32,
22761    status: &DiffHunkStatus,
22762    hunk_range: Range<Anchor>,
22763    is_created_file: bool,
22764    line_height: Pixels,
22765    editor: &Entity<Editor>,
22766    _window: &mut Window,
22767    cx: &mut App,
22768) -> AnyElement {
22769    h_flex()
22770        .h(line_height)
22771        .mr_1()
22772        .gap_1()
22773        .px_0p5()
22774        .pb_1()
22775        .border_x_1()
22776        .border_b_1()
22777        .border_color(cx.theme().colors().border_variant)
22778        .rounded_b_lg()
22779        .bg(cx.theme().colors().editor_background)
22780        .gap_1()
22781        .block_mouse_except_scroll()
22782        .shadow_md()
22783        .child(if status.has_secondary_hunk() {
22784            Button::new(("stage", row as u64), "Stage")
22785                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22786                .tooltip({
22787                    let focus_handle = editor.focus_handle(cx);
22788                    move |window, cx| {
22789                        Tooltip::for_action_in(
22790                            "Stage Hunk",
22791                            &::git::ToggleStaged,
22792                            &focus_handle,
22793                            window,
22794                            cx,
22795                        )
22796                    }
22797                })
22798                .on_click({
22799                    let editor = editor.clone();
22800                    move |_event, _window, cx| {
22801                        editor.update(cx, |editor, cx| {
22802                            editor.stage_or_unstage_diff_hunks(
22803                                true,
22804                                vec![hunk_range.start..hunk_range.start],
22805                                cx,
22806                            );
22807                        });
22808                    }
22809                })
22810        } else {
22811            Button::new(("unstage", row as u64), "Unstage")
22812                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22813                .tooltip({
22814                    let focus_handle = editor.focus_handle(cx);
22815                    move |window, cx| {
22816                        Tooltip::for_action_in(
22817                            "Unstage Hunk",
22818                            &::git::ToggleStaged,
22819                            &focus_handle,
22820                            window,
22821                            cx,
22822                        )
22823                    }
22824                })
22825                .on_click({
22826                    let editor = editor.clone();
22827                    move |_event, _window, cx| {
22828                        editor.update(cx, |editor, cx| {
22829                            editor.stage_or_unstage_diff_hunks(
22830                                false,
22831                                vec![hunk_range.start..hunk_range.start],
22832                                cx,
22833                            );
22834                        });
22835                    }
22836                })
22837        })
22838        .child(
22839            Button::new(("restore", row as u64), "Restore")
22840                .tooltip({
22841                    let focus_handle = editor.focus_handle(cx);
22842                    move |window, cx| {
22843                        Tooltip::for_action_in(
22844                            "Restore Hunk",
22845                            &::git::Restore,
22846                            &focus_handle,
22847                            window,
22848                            cx,
22849                        )
22850                    }
22851                })
22852                .on_click({
22853                    let editor = editor.clone();
22854                    move |_event, window, cx| {
22855                        editor.update(cx, |editor, cx| {
22856                            let snapshot = editor.snapshot(window, cx);
22857                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22858                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22859                        });
22860                    }
22861                })
22862                .disabled(is_created_file),
22863        )
22864        .when(
22865            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22866            |el| {
22867                el.child(
22868                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22869                        .shape(IconButtonShape::Square)
22870                        .icon_size(IconSize::Small)
22871                        // .disabled(!has_multiple_hunks)
22872                        .tooltip({
22873                            let focus_handle = editor.focus_handle(cx);
22874                            move |window, cx| {
22875                                Tooltip::for_action_in(
22876                                    "Next Hunk",
22877                                    &GoToHunk,
22878                                    &focus_handle,
22879                                    window,
22880                                    cx,
22881                                )
22882                            }
22883                        })
22884                        .on_click({
22885                            let editor = editor.clone();
22886                            move |_event, window, cx| {
22887                                editor.update(cx, |editor, cx| {
22888                                    let snapshot = editor.snapshot(window, cx);
22889                                    let position =
22890                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22891                                    editor.go_to_hunk_before_or_after_position(
22892                                        &snapshot,
22893                                        position,
22894                                        Direction::Next,
22895                                        window,
22896                                        cx,
22897                                    );
22898                                    editor.expand_selected_diff_hunks(cx);
22899                                });
22900                            }
22901                        }),
22902                )
22903                .child(
22904                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22905                        .shape(IconButtonShape::Square)
22906                        .icon_size(IconSize::Small)
22907                        // .disabled(!has_multiple_hunks)
22908                        .tooltip({
22909                            let focus_handle = editor.focus_handle(cx);
22910                            move |window, cx| {
22911                                Tooltip::for_action_in(
22912                                    "Previous Hunk",
22913                                    &GoToPreviousHunk,
22914                                    &focus_handle,
22915                                    window,
22916                                    cx,
22917                                )
22918                            }
22919                        })
22920                        .on_click({
22921                            let editor = editor.clone();
22922                            move |_event, window, cx| {
22923                                editor.update(cx, |editor, cx| {
22924                                    let snapshot = editor.snapshot(window, cx);
22925                                    let point =
22926                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22927                                    editor.go_to_hunk_before_or_after_position(
22928                                        &snapshot,
22929                                        point,
22930                                        Direction::Prev,
22931                                        window,
22932                                        cx,
22933                                    );
22934                                    editor.expand_selected_diff_hunks(cx);
22935                                });
22936                            }
22937                        }),
22938                )
22939            },
22940        )
22941        .into_any_element()
22942}