editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296pub enum PendingInput {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908enum SelectionDragState {
  909    /// State when no drag related activity is detected.
  910    None,
  911    /// State when the mouse is down on a selection that is about to be dragged.
  912    ReadyToDrag {
  913        selection: Selection<Anchor>,
  914        click_position: gpui::Point<Pixels>,
  915        mouse_down_time: Instant,
  916    },
  917    /// State when the mouse is dragging the selection in the editor.
  918    Dragging {
  919        selection: Selection<Anchor>,
  920        drop_cursor: Selection<Anchor>,
  921        hide_drop_cursor: bool,
  922    },
  923}
  924
  925/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  926/// a breakpoint on them.
  927#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  928struct PhantomBreakpointIndicator {
  929    display_row: DisplayRow,
  930    /// There's a small debounce between hovering over the line and showing the indicator.
  931    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  932    is_active: bool,
  933    collides_with_existing_breakpoint: bool,
  934}
  935
  936/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  937///
  938/// See the [module level documentation](self) for more information.
  939pub struct Editor {
  940    focus_handle: FocusHandle,
  941    last_focused_descendant: Option<WeakFocusHandle>,
  942    /// The text buffer being edited
  943    buffer: Entity<MultiBuffer>,
  944    /// Map of how text in the buffer should be displayed.
  945    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  946    pub display_map: Entity<DisplayMap>,
  947    pub selections: SelectionsCollection,
  948    pub scroll_manager: ScrollManager,
  949    /// When inline assist editors are linked, they all render cursors because
  950    /// typing enters text into each of them, even the ones that aren't focused.
  951    pub(crate) show_cursor_when_unfocused: bool,
  952    columnar_selection_tail: Option<Anchor>,
  953    columnar_display_point: Option<DisplayPoint>,
  954    add_selections_state: Option<AddSelectionsState>,
  955    select_next_state: Option<SelectNextState>,
  956    select_prev_state: Option<SelectNextState>,
  957    selection_history: SelectionHistory,
  958    defer_selection_effects: bool,
  959    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  960    autoclose_regions: Vec<AutocloseRegion>,
  961    snippet_stack: InvalidationStack<SnippetState>,
  962    select_syntax_node_history: SelectSyntaxNodeHistory,
  963    ime_transaction: Option<TransactionId>,
  964    pub diagnostics_max_severity: DiagnosticSeverity,
  965    active_diagnostics: ActiveDiagnostic,
  966    show_inline_diagnostics: bool,
  967    inline_diagnostics_update: Task<()>,
  968    inline_diagnostics_enabled: bool,
  969    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  970    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  971    hard_wrap: Option<usize>,
  972
  973    // TODO: make this a access method
  974    pub project: Option<Entity<Project>>,
  975    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  976    completion_provider: Option<Rc<dyn CompletionProvider>>,
  977    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  978    blink_manager: Entity<BlinkManager>,
  979    show_cursor_names: bool,
  980    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  981    pub show_local_selections: bool,
  982    mode: EditorMode,
  983    show_breadcrumbs: bool,
  984    show_gutter: bool,
  985    show_scrollbars: ScrollbarAxes,
  986    minimap_visibility: MinimapVisibility,
  987    offset_content: bool,
  988    disable_expand_excerpt_buttons: bool,
  989    show_line_numbers: Option<bool>,
  990    use_relative_line_numbers: Option<bool>,
  991    show_git_diff_gutter: Option<bool>,
  992    show_code_actions: Option<bool>,
  993    show_runnables: Option<bool>,
  994    show_breakpoints: Option<bool>,
  995    show_wrap_guides: Option<bool>,
  996    show_indent_guides: Option<bool>,
  997    placeholder_text: Option<Arc<str>>,
  998    highlight_order: usize,
  999    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1000    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1001    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1002    scrollbar_marker_state: ScrollbarMarkerState,
 1003    active_indent_guides_state: ActiveIndentGuidesState,
 1004    nav_history: Option<ItemNavHistory>,
 1005    context_menu: RefCell<Option<CodeContextMenu>>,
 1006    context_menu_options: Option<ContextMenuOptions>,
 1007    mouse_context_menu: Option<MouseContextMenu>,
 1008    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1009    inline_blame_popover: Option<InlineBlamePopover>,
 1010    signature_help_state: SignatureHelpState,
 1011    auto_signature_help: Option<bool>,
 1012    find_all_references_task_sources: Vec<Anchor>,
 1013    next_completion_id: CompletionId,
 1014    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1015    code_actions_task: Option<Task<Result<()>>>,
 1016    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1018    document_highlights_task: Option<Task<()>>,
 1019    linked_editing_range_task: Option<Task<Option<()>>>,
 1020    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1021    pending_rename: Option<RenameState>,
 1022    searchable: bool,
 1023    cursor_shape: CursorShape,
 1024    current_line_highlight: Option<CurrentLineHighlight>,
 1025    collapse_matches: bool,
 1026    autoindent_mode: Option<AutoindentMode>,
 1027    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1028    input_enabled: bool,
 1029    use_modal_editing: bool,
 1030    read_only: bool,
 1031    leader_id: Option<CollaboratorId>,
 1032    remote_id: Option<ViewId>,
 1033    pub hover_state: HoverState,
 1034    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1035    gutter_hovered: bool,
 1036    hovered_link_state: Option<HoveredLinkState>,
 1037    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1038    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1039    active_inline_completion: Option<InlineCompletionState>,
 1040    /// Used to prevent flickering as the user types while the menu is open
 1041    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1042    edit_prediction_settings: EditPredictionSettings,
 1043    inline_completions_hidden_for_vim_mode: bool,
 1044    show_inline_completions_override: Option<bool>,
 1045    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1046    edit_prediction_preview: EditPredictionPreview,
 1047    edit_prediction_indent_conflict: bool,
 1048    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1049    inlay_hint_cache: InlayHintCache,
 1050    next_inlay_id: usize,
 1051    _subscriptions: Vec<Subscription>,
 1052    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1053    gutter_dimensions: GutterDimensions,
 1054    style: Option<EditorStyle>,
 1055    text_style_refinement: Option<TextStyleRefinement>,
 1056    next_editor_action_id: EditorActionId,
 1057    editor_actions: Rc<
 1058        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1059    >,
 1060    use_autoclose: bool,
 1061    use_auto_surround: bool,
 1062    auto_replace_emoji_shortcode: bool,
 1063    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1064    show_git_blame_gutter: bool,
 1065    show_git_blame_inline: bool,
 1066    show_git_blame_inline_delay_task: Option<Task<()>>,
 1067    git_blame_inline_enabled: bool,
 1068    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1069    serialize_dirty_buffers: bool,
 1070    show_selection_menu: Option<bool>,
 1071    blame: Option<Entity<GitBlame>>,
 1072    blame_subscription: Option<Subscription>,
 1073    custom_context_menu: Option<
 1074        Box<
 1075            dyn 'static
 1076                + Fn(
 1077                    &mut Self,
 1078                    DisplayPoint,
 1079                    &mut Window,
 1080                    &mut Context<Self>,
 1081                ) -> Option<Entity<ui::ContextMenu>>,
 1082        >,
 1083    >,
 1084    last_bounds: Option<Bounds<Pixels>>,
 1085    last_position_map: Option<Rc<PositionMap>>,
 1086    expect_bounds_change: Option<Bounds<Pixels>>,
 1087    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1088    tasks_update_task: Option<Task<()>>,
 1089    breakpoint_store: Option<Entity<BreakpointStore>>,
 1090    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1091    pull_diagnostics_task: Task<()>,
 1092    in_project_search: bool,
 1093    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1094    breadcrumb_header: Option<String>,
 1095    focused_block: Option<FocusedBlock>,
 1096    next_scroll_position: NextScrollCursorCenterTopBottom,
 1097    addons: HashMap<TypeId, Box<dyn Addon>>,
 1098    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1099    load_diff_task: Option<Shared<Task<()>>>,
 1100    /// Whether we are temporarily displaying a diff other than git's
 1101    temporary_diff_override: bool,
 1102    selection_mark_mode: bool,
 1103    toggle_fold_multiple_buffers: Task<()>,
 1104    _scroll_cursor_center_top_bottom_task: Task<()>,
 1105    serialize_selections: Task<()>,
 1106    serialize_folds: Task<()>,
 1107    mouse_cursor_hidden: bool,
 1108    minimap: Option<Entity<Self>>,
 1109    hide_mouse_mode: HideMouseMode,
 1110    pub change_list: ChangeList,
 1111    inline_value_cache: InlineValueCache,
 1112    selection_drag_state: SelectionDragState,
 1113    drag_and_drop_selection_enabled: bool,
 1114}
 1115
 1116#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1117enum NextScrollCursorCenterTopBottom {
 1118    #[default]
 1119    Center,
 1120    Top,
 1121    Bottom,
 1122}
 1123
 1124impl NextScrollCursorCenterTopBottom {
 1125    fn next(&self) -> Self {
 1126        match self {
 1127            Self::Center => Self::Top,
 1128            Self::Top => Self::Bottom,
 1129            Self::Bottom => Self::Center,
 1130        }
 1131    }
 1132}
 1133
 1134#[derive(Clone)]
 1135pub struct EditorSnapshot {
 1136    pub mode: EditorMode,
 1137    show_gutter: bool,
 1138    show_line_numbers: Option<bool>,
 1139    show_git_diff_gutter: Option<bool>,
 1140    show_code_actions: Option<bool>,
 1141    show_runnables: Option<bool>,
 1142    show_breakpoints: Option<bool>,
 1143    git_blame_gutter_max_author_length: Option<usize>,
 1144    pub display_snapshot: DisplaySnapshot,
 1145    pub placeholder_text: Option<Arc<str>>,
 1146    is_focused: bool,
 1147    scroll_anchor: ScrollAnchor,
 1148    ongoing_scroll: OngoingScroll,
 1149    current_line_highlight: CurrentLineHighlight,
 1150    gutter_hovered: bool,
 1151}
 1152
 1153#[derive(Default, Debug, Clone, Copy)]
 1154pub struct GutterDimensions {
 1155    pub left_padding: Pixels,
 1156    pub right_padding: Pixels,
 1157    pub width: Pixels,
 1158    pub margin: Pixels,
 1159    pub git_blame_entries_width: Option<Pixels>,
 1160}
 1161
 1162impl GutterDimensions {
 1163    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1164        Self {
 1165            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1166            ..Default::default()
 1167        }
 1168    }
 1169
 1170    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1171        -cx.text_system().descent(font_id, font_size)
 1172    }
 1173    /// The full width of the space taken up by the gutter.
 1174    pub fn full_width(&self) -> Pixels {
 1175        self.margin + self.width
 1176    }
 1177
 1178    /// The width of the space reserved for the fold indicators,
 1179    /// use alongside 'justify_end' and `gutter_width` to
 1180    /// right align content with the line numbers
 1181    pub fn fold_area_width(&self) -> Pixels {
 1182        self.margin + self.right_padding
 1183    }
 1184}
 1185
 1186#[derive(Debug)]
 1187pub struct RemoteSelection {
 1188    pub replica_id: ReplicaId,
 1189    pub selection: Selection<Anchor>,
 1190    pub cursor_shape: CursorShape,
 1191    pub collaborator_id: CollaboratorId,
 1192    pub line_mode: bool,
 1193    pub user_name: Option<SharedString>,
 1194    pub color: PlayerColor,
 1195}
 1196
 1197#[derive(Clone, Debug)]
 1198struct SelectionHistoryEntry {
 1199    selections: Arc<[Selection<Anchor>]>,
 1200    select_next_state: Option<SelectNextState>,
 1201    select_prev_state: Option<SelectNextState>,
 1202    add_selections_state: Option<AddSelectionsState>,
 1203}
 1204
 1205#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1206enum SelectionHistoryMode {
 1207    Normal,
 1208    Undoing,
 1209    Redoing,
 1210    Skipping,
 1211}
 1212
 1213#[derive(Clone, PartialEq, Eq, Hash)]
 1214struct HoveredCursor {
 1215    replica_id: u16,
 1216    selection_id: usize,
 1217}
 1218
 1219impl Default for SelectionHistoryMode {
 1220    fn default() -> Self {
 1221        Self::Normal
 1222    }
 1223}
 1224
 1225#[derive(Debug)]
 1226pub struct SelectionEffects {
 1227    nav_history: bool,
 1228    completions: bool,
 1229    scroll: Option<Autoscroll>,
 1230}
 1231
 1232impl Default for SelectionEffects {
 1233    fn default() -> Self {
 1234        Self {
 1235            nav_history: true,
 1236            completions: true,
 1237            scroll: Some(Autoscroll::fit()),
 1238        }
 1239    }
 1240}
 1241impl SelectionEffects {
 1242    pub fn scroll(scroll: Autoscroll) -> Self {
 1243        Self {
 1244            scroll: Some(scroll),
 1245            ..Default::default()
 1246        }
 1247    }
 1248
 1249    pub fn no_scroll() -> Self {
 1250        Self {
 1251            scroll: None,
 1252            ..Default::default()
 1253        }
 1254    }
 1255
 1256    pub fn completions(self, completions: bool) -> Self {
 1257        Self {
 1258            completions,
 1259            ..self
 1260        }
 1261    }
 1262
 1263    pub fn nav_history(self, nav_history: bool) -> Self {
 1264        Self {
 1265            nav_history,
 1266            ..self
 1267        }
 1268    }
 1269}
 1270
 1271struct DeferredSelectionEffectsState {
 1272    changed: bool,
 1273    effects: SelectionEffects,
 1274    old_cursor_position: Anchor,
 1275    history_entry: SelectionHistoryEntry,
 1276}
 1277
 1278#[derive(Default)]
 1279struct SelectionHistory {
 1280    #[allow(clippy::type_complexity)]
 1281    selections_by_transaction:
 1282        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1283    mode: SelectionHistoryMode,
 1284    undo_stack: VecDeque<SelectionHistoryEntry>,
 1285    redo_stack: VecDeque<SelectionHistoryEntry>,
 1286}
 1287
 1288impl SelectionHistory {
 1289    #[track_caller]
 1290    fn insert_transaction(
 1291        &mut self,
 1292        transaction_id: TransactionId,
 1293        selections: Arc<[Selection<Anchor>]>,
 1294    ) {
 1295        if selections.is_empty() {
 1296            log::error!(
 1297                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1298                std::panic::Location::caller()
 1299            );
 1300            return;
 1301        }
 1302        self.selections_by_transaction
 1303            .insert(transaction_id, (selections, None));
 1304    }
 1305
 1306    #[allow(clippy::type_complexity)]
 1307    fn transaction(
 1308        &self,
 1309        transaction_id: TransactionId,
 1310    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1311        self.selections_by_transaction.get(&transaction_id)
 1312    }
 1313
 1314    #[allow(clippy::type_complexity)]
 1315    fn transaction_mut(
 1316        &mut self,
 1317        transaction_id: TransactionId,
 1318    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1319        self.selections_by_transaction.get_mut(&transaction_id)
 1320    }
 1321
 1322    fn push(&mut self, entry: SelectionHistoryEntry) {
 1323        if !entry.selections.is_empty() {
 1324            match self.mode {
 1325                SelectionHistoryMode::Normal => {
 1326                    self.push_undo(entry);
 1327                    self.redo_stack.clear();
 1328                }
 1329                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1330                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1331                SelectionHistoryMode::Skipping => {}
 1332            }
 1333        }
 1334    }
 1335
 1336    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1337        if self
 1338            .undo_stack
 1339            .back()
 1340            .map_or(true, |e| e.selections != entry.selections)
 1341        {
 1342            self.undo_stack.push_back(entry);
 1343            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1344                self.undo_stack.pop_front();
 1345            }
 1346        }
 1347    }
 1348
 1349    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1350        if self
 1351            .redo_stack
 1352            .back()
 1353            .map_or(true, |e| e.selections != entry.selections)
 1354        {
 1355            self.redo_stack.push_back(entry);
 1356            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1357                self.redo_stack.pop_front();
 1358            }
 1359        }
 1360    }
 1361}
 1362
 1363#[derive(Clone, Copy)]
 1364pub struct RowHighlightOptions {
 1365    pub autoscroll: bool,
 1366    pub include_gutter: bool,
 1367}
 1368
 1369impl Default for RowHighlightOptions {
 1370    fn default() -> Self {
 1371        Self {
 1372            autoscroll: Default::default(),
 1373            include_gutter: true,
 1374        }
 1375    }
 1376}
 1377
 1378struct RowHighlight {
 1379    index: usize,
 1380    range: Range<Anchor>,
 1381    color: Hsla,
 1382    options: RowHighlightOptions,
 1383    type_id: TypeId,
 1384}
 1385
 1386#[derive(Clone, Debug)]
 1387struct AddSelectionsState {
 1388    groups: Vec<AddSelectionsGroup>,
 1389}
 1390
 1391#[derive(Clone, Debug)]
 1392struct AddSelectionsGroup {
 1393    above: bool,
 1394    stack: Vec<usize>,
 1395}
 1396
 1397#[derive(Clone)]
 1398struct SelectNextState {
 1399    query: AhoCorasick,
 1400    wordwise: bool,
 1401    done: bool,
 1402}
 1403
 1404impl std::fmt::Debug for SelectNextState {
 1405    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1406        f.debug_struct(std::any::type_name::<Self>())
 1407            .field("wordwise", &self.wordwise)
 1408            .field("done", &self.done)
 1409            .finish()
 1410    }
 1411}
 1412
 1413#[derive(Debug)]
 1414struct AutocloseRegion {
 1415    selection_id: usize,
 1416    range: Range<Anchor>,
 1417    pair: BracketPair,
 1418}
 1419
 1420#[derive(Debug)]
 1421struct SnippetState {
 1422    ranges: Vec<Vec<Range<Anchor>>>,
 1423    active_index: usize,
 1424    choices: Vec<Option<Vec<String>>>,
 1425}
 1426
 1427#[doc(hidden)]
 1428pub struct RenameState {
 1429    pub range: Range<Anchor>,
 1430    pub old_name: Arc<str>,
 1431    pub editor: Entity<Editor>,
 1432    block_id: CustomBlockId,
 1433}
 1434
 1435struct InvalidationStack<T>(Vec<T>);
 1436
 1437struct RegisteredInlineCompletionProvider {
 1438    provider: Arc<dyn InlineCompletionProviderHandle>,
 1439    _subscription: Subscription,
 1440}
 1441
 1442#[derive(Debug, PartialEq, Eq)]
 1443pub struct ActiveDiagnosticGroup {
 1444    pub active_range: Range<Anchor>,
 1445    pub active_message: String,
 1446    pub group_id: usize,
 1447    pub blocks: HashSet<CustomBlockId>,
 1448}
 1449
 1450#[derive(Debug, PartialEq, Eq)]
 1451
 1452pub(crate) enum ActiveDiagnostic {
 1453    None,
 1454    All,
 1455    Group(ActiveDiagnosticGroup),
 1456}
 1457
 1458#[derive(Serialize, Deserialize, Clone, Debug)]
 1459pub struct ClipboardSelection {
 1460    /// The number of bytes in this selection.
 1461    pub len: usize,
 1462    /// Whether this was a full-line selection.
 1463    pub is_entire_line: bool,
 1464    /// The indentation of the first line when this content was originally copied.
 1465    pub first_line_indent: u32,
 1466}
 1467
 1468// selections, scroll behavior, was newest selection reversed
 1469type SelectSyntaxNodeHistoryState = (
 1470    Box<[Selection<usize>]>,
 1471    SelectSyntaxNodeScrollBehavior,
 1472    bool,
 1473);
 1474
 1475#[derive(Default)]
 1476struct SelectSyntaxNodeHistory {
 1477    stack: Vec<SelectSyntaxNodeHistoryState>,
 1478    // disable temporarily to allow changing selections without losing the stack
 1479    pub disable_clearing: bool,
 1480}
 1481
 1482impl SelectSyntaxNodeHistory {
 1483    pub fn try_clear(&mut self) {
 1484        if !self.disable_clearing {
 1485            self.stack.clear();
 1486        }
 1487    }
 1488
 1489    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1490        self.stack.push(selection);
 1491    }
 1492
 1493    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1494        self.stack.pop()
 1495    }
 1496}
 1497
 1498enum SelectSyntaxNodeScrollBehavior {
 1499    CursorTop,
 1500    FitSelection,
 1501    CursorBottom,
 1502}
 1503
 1504#[derive(Debug)]
 1505pub(crate) struct NavigationData {
 1506    cursor_anchor: Anchor,
 1507    cursor_position: Point,
 1508    scroll_anchor: ScrollAnchor,
 1509    scroll_top_row: u32,
 1510}
 1511
 1512#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1513pub enum GotoDefinitionKind {
 1514    Symbol,
 1515    Declaration,
 1516    Type,
 1517    Implementation,
 1518}
 1519
 1520#[derive(Debug, Clone)]
 1521enum InlayHintRefreshReason {
 1522    ModifiersChanged(bool),
 1523    Toggle(bool),
 1524    SettingsChange(InlayHintSettings),
 1525    NewLinesShown,
 1526    BufferEdited(HashSet<Arc<Language>>),
 1527    RefreshRequested,
 1528    ExcerptsRemoved(Vec<ExcerptId>),
 1529}
 1530
 1531impl InlayHintRefreshReason {
 1532    fn description(&self) -> &'static str {
 1533        match self {
 1534            Self::ModifiersChanged(_) => "modifiers changed",
 1535            Self::Toggle(_) => "toggle",
 1536            Self::SettingsChange(_) => "settings change",
 1537            Self::NewLinesShown => "new lines shown",
 1538            Self::BufferEdited(_) => "buffer edited",
 1539            Self::RefreshRequested => "refresh requested",
 1540            Self::ExcerptsRemoved(_) => "excerpts removed",
 1541        }
 1542    }
 1543}
 1544
 1545pub enum FormatTarget {
 1546    Buffers(HashSet<Entity<Buffer>>),
 1547    Ranges(Vec<Range<MultiBufferPoint>>),
 1548}
 1549
 1550pub(crate) struct FocusedBlock {
 1551    id: BlockId,
 1552    focus_handle: WeakFocusHandle,
 1553}
 1554
 1555#[derive(Clone)]
 1556enum JumpData {
 1557    MultiBufferRow {
 1558        row: MultiBufferRow,
 1559        line_offset_from_top: u32,
 1560    },
 1561    MultiBufferPoint {
 1562        excerpt_id: ExcerptId,
 1563        position: Point,
 1564        anchor: text::Anchor,
 1565        line_offset_from_top: u32,
 1566    },
 1567}
 1568
 1569pub enum MultibufferSelectionMode {
 1570    First,
 1571    All,
 1572}
 1573
 1574#[derive(Clone, Copy, Debug, Default)]
 1575pub struct RewrapOptions {
 1576    pub override_language_settings: bool,
 1577    pub preserve_existing_whitespace: bool,
 1578}
 1579
 1580impl Editor {
 1581    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1582        let buffer = cx.new(|cx| Buffer::local("", cx));
 1583        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1584        Self::new(
 1585            EditorMode::SingleLine { auto_width: false },
 1586            buffer,
 1587            None,
 1588            window,
 1589            cx,
 1590        )
 1591    }
 1592
 1593    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1594        let buffer = cx.new(|cx| Buffer::local("", cx));
 1595        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1596        Self::new(EditorMode::full(), buffer, None, window, cx)
 1597    }
 1598
 1599    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1600        let buffer = cx.new(|cx| Buffer::local("", cx));
 1601        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1602        Self::new(
 1603            EditorMode::SingleLine { auto_width: true },
 1604            buffer,
 1605            None,
 1606            window,
 1607            cx,
 1608        )
 1609    }
 1610
 1611    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1612        let buffer = cx.new(|cx| Buffer::local("", cx));
 1613        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1614        Self::new(
 1615            EditorMode::AutoHeight { max_lines },
 1616            buffer,
 1617            None,
 1618            window,
 1619            cx,
 1620        )
 1621    }
 1622
 1623    pub fn for_buffer(
 1624        buffer: Entity<Buffer>,
 1625        project: Option<Entity<Project>>,
 1626        window: &mut Window,
 1627        cx: &mut Context<Self>,
 1628    ) -> Self {
 1629        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1630        Self::new(EditorMode::full(), buffer, project, window, cx)
 1631    }
 1632
 1633    pub fn for_multibuffer(
 1634        buffer: Entity<MultiBuffer>,
 1635        project: Option<Entity<Project>>,
 1636        window: &mut Window,
 1637        cx: &mut Context<Self>,
 1638    ) -> Self {
 1639        Self::new(EditorMode::full(), buffer, project, window, cx)
 1640    }
 1641
 1642    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1643        let mut clone = Self::new(
 1644            self.mode.clone(),
 1645            self.buffer.clone(),
 1646            self.project.clone(),
 1647            window,
 1648            cx,
 1649        );
 1650        self.display_map.update(cx, |display_map, cx| {
 1651            let snapshot = display_map.snapshot(cx);
 1652            clone.display_map.update(cx, |display_map, cx| {
 1653                display_map.set_state(&snapshot, cx);
 1654            });
 1655        });
 1656        clone.folds_did_change(cx);
 1657        clone.selections.clone_state(&self.selections);
 1658        clone.scroll_manager.clone_state(&self.scroll_manager);
 1659        clone.searchable = self.searchable;
 1660        clone.read_only = self.read_only;
 1661        clone
 1662    }
 1663
 1664    pub fn new(
 1665        mode: EditorMode,
 1666        buffer: Entity<MultiBuffer>,
 1667        project: Option<Entity<Project>>,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        Editor::new_internal(mode, buffer, project, None, window, cx)
 1672    }
 1673
 1674    fn new_internal(
 1675        mode: EditorMode,
 1676        buffer: Entity<MultiBuffer>,
 1677        project: Option<Entity<Project>>,
 1678        display_map: Option<Entity<DisplayMap>>,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        debug_assert!(
 1683            display_map.is_none() || mode.is_minimap(),
 1684            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1685        );
 1686
 1687        let full_mode = mode.is_full();
 1688        let diagnostics_max_severity = if full_mode {
 1689            EditorSettings::get_global(cx)
 1690                .diagnostics_max_severity
 1691                .unwrap_or(DiagnosticSeverity::Hint)
 1692        } else {
 1693            DiagnosticSeverity::Off
 1694        };
 1695        let style = window.text_style();
 1696        let font_size = style.font_size.to_pixels(window.rem_size());
 1697        let editor = cx.entity().downgrade();
 1698        let fold_placeholder = FoldPlaceholder {
 1699            constrain_width: true,
 1700            render: Arc::new(move |fold_id, fold_range, cx| {
 1701                let editor = editor.clone();
 1702                div()
 1703                    .id(fold_id)
 1704                    .bg(cx.theme().colors().ghost_element_background)
 1705                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1706                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1707                    .rounded_xs()
 1708                    .size_full()
 1709                    .cursor_pointer()
 1710                    .child("")
 1711                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1712                    .on_click(move |_, _window, cx| {
 1713                        editor
 1714                            .update(cx, |editor, cx| {
 1715                                editor.unfold_ranges(
 1716                                    &[fold_range.start..fold_range.end],
 1717                                    true,
 1718                                    false,
 1719                                    cx,
 1720                                );
 1721                                cx.stop_propagation();
 1722                            })
 1723                            .ok();
 1724                    })
 1725                    .into_any()
 1726            }),
 1727            merge_adjacent: true,
 1728            ..FoldPlaceholder::default()
 1729        };
 1730        let display_map = display_map.unwrap_or_else(|| {
 1731            cx.new(|cx| {
 1732                DisplayMap::new(
 1733                    buffer.clone(),
 1734                    style.font(),
 1735                    font_size,
 1736                    None,
 1737                    FILE_HEADER_HEIGHT,
 1738                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1739                    fold_placeholder,
 1740                    diagnostics_max_severity,
 1741                    cx,
 1742                )
 1743            })
 1744        });
 1745
 1746        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1747
 1748        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1749
 1750        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1751            .then(|| language_settings::SoftWrap::None);
 1752
 1753        let mut project_subscriptions = Vec::new();
 1754        if mode.is_full() {
 1755            if let Some(project) = project.as_ref() {
 1756                project_subscriptions.push(cx.subscribe_in(
 1757                    project,
 1758                    window,
 1759                    |editor, _, event, window, cx| match event {
 1760                        project::Event::RefreshCodeLens => {
 1761                            // we always query lens with actions, without storing them, always refreshing them
 1762                        }
 1763                        project::Event::RefreshInlayHints => {
 1764                            editor
 1765                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1766                        }
 1767                        project::Event::LanguageServerAdded(..)
 1768                        | project::Event::LanguageServerRemoved(..) => {
 1769                            if editor.tasks_update_task.is_none() {
 1770                                editor.tasks_update_task =
 1771                                    Some(editor.refresh_runnables(window, cx));
 1772                            }
 1773                            editor.pull_diagnostics(None, window, cx);
 1774                        }
 1775                        project::Event::SnippetEdit(id, snippet_edits) => {
 1776                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1777                                let focus_handle = editor.focus_handle(cx);
 1778                                if focus_handle.is_focused(window) {
 1779                                    let snapshot = buffer.read(cx).snapshot();
 1780                                    for (range, snippet) in snippet_edits {
 1781                                        let editor_range =
 1782                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1783                                        editor
 1784                                            .insert_snippet(
 1785                                                &[editor_range],
 1786                                                snippet.clone(),
 1787                                                window,
 1788                                                cx,
 1789                                            )
 1790                                            .ok();
 1791                                    }
 1792                                }
 1793                            }
 1794                        }
 1795                        _ => {}
 1796                    },
 1797                ));
 1798                if let Some(task_inventory) = project
 1799                    .read(cx)
 1800                    .task_store()
 1801                    .read(cx)
 1802                    .task_inventory()
 1803                    .cloned()
 1804                {
 1805                    project_subscriptions.push(cx.observe_in(
 1806                        &task_inventory,
 1807                        window,
 1808                        |editor, _, window, cx| {
 1809                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1810                        },
 1811                    ));
 1812                };
 1813
 1814                project_subscriptions.push(cx.subscribe_in(
 1815                    &project.read(cx).breakpoint_store(),
 1816                    window,
 1817                    |editor, _, event, window, cx| match event {
 1818                        BreakpointStoreEvent::ClearDebugLines => {
 1819                            editor.clear_row_highlights::<ActiveDebugLine>();
 1820                            editor.refresh_inline_values(cx);
 1821                        }
 1822                        BreakpointStoreEvent::SetDebugLine => {
 1823                            if editor.go_to_active_debug_line(window, cx) {
 1824                                cx.stop_propagation();
 1825                            }
 1826
 1827                            editor.refresh_inline_values(cx);
 1828                        }
 1829                        _ => {}
 1830                    },
 1831                ));
 1832            }
 1833        }
 1834
 1835        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1836
 1837        let inlay_hint_settings =
 1838            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1839        let focus_handle = cx.focus_handle();
 1840        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1841            .detach();
 1842        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1843            .detach();
 1844        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1845            .detach();
 1846        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1847            .detach();
 1848        cx.observe_pending_input(window, Self::observe_pending_input)
 1849            .detach();
 1850
 1851        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1852            Some(false)
 1853        } else {
 1854            None
 1855        };
 1856
 1857        let breakpoint_store = match (&mode, project.as_ref()) {
 1858            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1859            _ => None,
 1860        };
 1861
 1862        let mut code_action_providers = Vec::new();
 1863        let mut load_uncommitted_diff = None;
 1864        if let Some(project) = project.clone() {
 1865            load_uncommitted_diff = Some(
 1866                update_uncommitted_diff_for_buffer(
 1867                    cx.entity(),
 1868                    &project,
 1869                    buffer.read(cx).all_buffers(),
 1870                    buffer.clone(),
 1871                    cx,
 1872                )
 1873                .shared(),
 1874            );
 1875            code_action_providers.push(Rc::new(project) as Rc<_>);
 1876        }
 1877
 1878        let mut editor = Self {
 1879            focus_handle,
 1880            show_cursor_when_unfocused: false,
 1881            last_focused_descendant: None,
 1882            buffer: buffer.clone(),
 1883            display_map: display_map.clone(),
 1884            selections,
 1885            scroll_manager: ScrollManager::new(cx),
 1886            columnar_selection_tail: None,
 1887            columnar_display_point: None,
 1888            add_selections_state: None,
 1889            select_next_state: None,
 1890            select_prev_state: None,
 1891            selection_history: SelectionHistory::default(),
 1892            defer_selection_effects: false,
 1893            deferred_selection_effects_state: None,
 1894            autoclose_regions: Vec::new(),
 1895            snippet_stack: InvalidationStack::default(),
 1896            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1897            ime_transaction: None,
 1898            active_diagnostics: ActiveDiagnostic::None,
 1899            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1900            inline_diagnostics_update: Task::ready(()),
 1901            inline_diagnostics: Vec::new(),
 1902            soft_wrap_mode_override,
 1903            diagnostics_max_severity,
 1904            hard_wrap: None,
 1905            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1906            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1907            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1908            project,
 1909            blink_manager: blink_manager.clone(),
 1910            show_local_selections: true,
 1911            show_scrollbars: ScrollbarAxes {
 1912                horizontal: full_mode,
 1913                vertical: full_mode,
 1914            },
 1915            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1916            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1917            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1918            show_gutter: mode.is_full(),
 1919            show_line_numbers: None,
 1920            use_relative_line_numbers: None,
 1921            disable_expand_excerpt_buttons: false,
 1922            show_git_diff_gutter: None,
 1923            show_code_actions: None,
 1924            show_runnables: None,
 1925            show_breakpoints: None,
 1926            show_wrap_guides: None,
 1927            show_indent_guides,
 1928            placeholder_text: None,
 1929            highlight_order: 0,
 1930            highlighted_rows: HashMap::default(),
 1931            background_highlights: TreeMap::default(),
 1932            gutter_highlights: TreeMap::default(),
 1933            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1934            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1935            nav_history: None,
 1936            context_menu: RefCell::new(None),
 1937            context_menu_options: None,
 1938            mouse_context_menu: None,
 1939            completion_tasks: Vec::new(),
 1940            inline_blame_popover: None,
 1941            signature_help_state: SignatureHelpState::default(),
 1942            auto_signature_help: None,
 1943            find_all_references_task_sources: Vec::new(),
 1944            next_completion_id: 0,
 1945            next_inlay_id: 0,
 1946            code_action_providers,
 1947            available_code_actions: None,
 1948            code_actions_task: None,
 1949            quick_selection_highlight_task: None,
 1950            debounced_selection_highlight_task: None,
 1951            document_highlights_task: None,
 1952            linked_editing_range_task: None,
 1953            pending_rename: None,
 1954            searchable: true,
 1955            cursor_shape: EditorSettings::get_global(cx)
 1956                .cursor_shape
 1957                .unwrap_or_default(),
 1958            current_line_highlight: None,
 1959            autoindent_mode: Some(AutoindentMode::EachLine),
 1960            collapse_matches: false,
 1961            workspace: None,
 1962            input_enabled: true,
 1963            use_modal_editing: mode.is_full(),
 1964            read_only: mode.is_minimap(),
 1965            use_autoclose: true,
 1966            use_auto_surround: true,
 1967            auto_replace_emoji_shortcode: false,
 1968            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1969            leader_id: None,
 1970            remote_id: None,
 1971            hover_state: HoverState::default(),
 1972            pending_mouse_down: None,
 1973            hovered_link_state: None,
 1974            edit_prediction_provider: None,
 1975            active_inline_completion: None,
 1976            stale_inline_completion_in_menu: None,
 1977            edit_prediction_preview: EditPredictionPreview::Inactive {
 1978                released_too_fast: false,
 1979            },
 1980            inline_diagnostics_enabled: mode.is_full(),
 1981            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1982            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1983
 1984            gutter_hovered: false,
 1985            pixel_position_of_newest_cursor: None,
 1986            last_bounds: None,
 1987            last_position_map: None,
 1988            expect_bounds_change: None,
 1989            gutter_dimensions: GutterDimensions::default(),
 1990            style: None,
 1991            show_cursor_names: false,
 1992            hovered_cursors: HashMap::default(),
 1993            next_editor_action_id: EditorActionId::default(),
 1994            editor_actions: Rc::default(),
 1995            inline_completions_hidden_for_vim_mode: false,
 1996            show_inline_completions_override: None,
 1997            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1998            edit_prediction_settings: EditPredictionSettings::Disabled,
 1999            edit_prediction_indent_conflict: false,
 2000            edit_prediction_requires_modifier_in_indent_conflict: true,
 2001            custom_context_menu: None,
 2002            show_git_blame_gutter: false,
 2003            show_git_blame_inline: false,
 2004            show_selection_menu: None,
 2005            show_git_blame_inline_delay_task: None,
 2006            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2007            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2008            serialize_dirty_buffers: !mode.is_minimap()
 2009                && ProjectSettings::get_global(cx)
 2010                    .session
 2011                    .restore_unsaved_buffers,
 2012            blame: None,
 2013            blame_subscription: None,
 2014            tasks: BTreeMap::default(),
 2015
 2016            breakpoint_store,
 2017            gutter_breakpoint_indicator: (None, None),
 2018            _subscriptions: vec![
 2019                cx.observe(&buffer, Self::on_buffer_changed),
 2020                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2021                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2022                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2023                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2024                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2025                cx.observe_window_activation(window, |editor, window, cx| {
 2026                    let active = window.is_window_active();
 2027                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2028                        if active {
 2029                            blink_manager.enable(cx);
 2030                        } else {
 2031                            blink_manager.disable(cx);
 2032                        }
 2033                    });
 2034                    if active {
 2035                        editor.show_mouse_cursor();
 2036                    }
 2037                }),
 2038            ],
 2039            tasks_update_task: None,
 2040            pull_diagnostics_task: Task::ready(()),
 2041            linked_edit_ranges: Default::default(),
 2042            in_project_search: false,
 2043            previous_search_ranges: None,
 2044            breadcrumb_header: None,
 2045            focused_block: None,
 2046            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2047            addons: HashMap::default(),
 2048            registered_buffers: HashMap::default(),
 2049            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2050            selection_mark_mode: false,
 2051            toggle_fold_multiple_buffers: Task::ready(()),
 2052            serialize_selections: Task::ready(()),
 2053            serialize_folds: Task::ready(()),
 2054            text_style_refinement: None,
 2055            load_diff_task: load_uncommitted_diff,
 2056            temporary_diff_override: false,
 2057            mouse_cursor_hidden: false,
 2058            minimap: None,
 2059            hide_mouse_mode: EditorSettings::get_global(cx)
 2060                .hide_mouse
 2061                .unwrap_or_default(),
 2062            change_list: ChangeList::new(),
 2063            mode,
 2064            selection_drag_state: SelectionDragState::None,
 2065            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2066        };
 2067        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2068            editor
 2069                ._subscriptions
 2070                .push(cx.observe(breakpoints, |_, _, cx| {
 2071                    cx.notify();
 2072                }));
 2073        }
 2074        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2075        editor._subscriptions.extend(project_subscriptions);
 2076
 2077        editor._subscriptions.push(cx.subscribe_in(
 2078            &cx.entity(),
 2079            window,
 2080            |editor, _, e: &EditorEvent, window, cx| match e {
 2081                EditorEvent::ScrollPositionChanged { local, .. } => {
 2082                    if *local {
 2083                        let new_anchor = editor.scroll_manager.anchor();
 2084                        let snapshot = editor.snapshot(window, cx);
 2085                        editor.update_restoration_data(cx, move |data| {
 2086                            data.scroll_position = (
 2087                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2088                                new_anchor.offset,
 2089                            );
 2090                        });
 2091                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2092                        editor.inline_blame_popover.take();
 2093                    }
 2094                }
 2095                EditorEvent::Edited { .. } => {
 2096                    if !vim_enabled(cx) {
 2097                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2098                        let pop_state = editor
 2099                            .change_list
 2100                            .last()
 2101                            .map(|previous| {
 2102                                previous.len() == selections.len()
 2103                                    && previous.iter().enumerate().all(|(ix, p)| {
 2104                                        p.to_display_point(&map).row()
 2105                                            == selections[ix].head().row()
 2106                                    })
 2107                            })
 2108                            .unwrap_or(false);
 2109                        let new_positions = selections
 2110                            .into_iter()
 2111                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2112                            .collect();
 2113                        editor
 2114                            .change_list
 2115                            .push_to_change_list(pop_state, new_positions);
 2116                    }
 2117                }
 2118                _ => (),
 2119            },
 2120        ));
 2121
 2122        if let Some(dap_store) = editor
 2123            .project
 2124            .as_ref()
 2125            .map(|project| project.read(cx).dap_store())
 2126        {
 2127            let weak_editor = cx.weak_entity();
 2128
 2129            editor
 2130                ._subscriptions
 2131                .push(
 2132                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2133                        let session_entity = cx.entity();
 2134                        weak_editor
 2135                            .update(cx, |editor, cx| {
 2136                                editor._subscriptions.push(
 2137                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2138                                );
 2139                            })
 2140                            .ok();
 2141                    }),
 2142                );
 2143
 2144            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2145                editor
 2146                    ._subscriptions
 2147                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2148            }
 2149        }
 2150
 2151        // skip adding the initial selection to selection history
 2152        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2153        editor.end_selection(window, cx);
 2154        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2155
 2156        editor.scroll_manager.show_scrollbars(window, cx);
 2157        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2158
 2159        if full_mode {
 2160            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2161            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2162
 2163            if editor.git_blame_inline_enabled {
 2164                editor.start_git_blame_inline(false, window, cx);
 2165            }
 2166
 2167            editor.go_to_active_debug_line(window, cx);
 2168
 2169            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2170                if let Some(project) = editor.project.as_ref() {
 2171                    let handle = project.update(cx, |project, cx| {
 2172                        project.register_buffer_with_language_servers(&buffer, cx)
 2173                    });
 2174                    editor
 2175                        .registered_buffers
 2176                        .insert(buffer.read(cx).remote_id(), handle);
 2177                }
 2178            }
 2179
 2180            editor.minimap =
 2181                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2182            editor.pull_diagnostics(None, window, cx);
 2183        }
 2184
 2185        editor.report_editor_event("Editor Opened", None, cx);
 2186        editor
 2187    }
 2188
 2189    pub fn deploy_mouse_context_menu(
 2190        &mut self,
 2191        position: gpui::Point<Pixels>,
 2192        context_menu: Entity<ContextMenu>,
 2193        window: &mut Window,
 2194        cx: &mut Context<Self>,
 2195    ) {
 2196        self.mouse_context_menu = Some(MouseContextMenu::new(
 2197            self,
 2198            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2199            context_menu,
 2200            window,
 2201            cx,
 2202        ));
 2203    }
 2204
 2205    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2206        self.mouse_context_menu
 2207            .as_ref()
 2208            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2209    }
 2210
 2211    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2212        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2213    }
 2214
 2215    fn key_context_internal(
 2216        &self,
 2217        has_active_edit_prediction: bool,
 2218        window: &Window,
 2219        cx: &App,
 2220    ) -> KeyContext {
 2221        let mut key_context = KeyContext::new_with_defaults();
 2222        key_context.add("Editor");
 2223        let mode = match self.mode {
 2224            EditorMode::SingleLine { .. } => "single_line",
 2225            EditorMode::AutoHeight { .. } => "auto_height",
 2226            EditorMode::Minimap { .. } => "minimap",
 2227            EditorMode::Full { .. } => "full",
 2228        };
 2229
 2230        if EditorSettings::jupyter_enabled(cx) {
 2231            key_context.add("jupyter");
 2232        }
 2233
 2234        key_context.set("mode", mode);
 2235        if self.pending_rename.is_some() {
 2236            key_context.add("renaming");
 2237        }
 2238
 2239        match self.context_menu.borrow().as_ref() {
 2240            Some(CodeContextMenu::Completions(_)) => {
 2241                key_context.add("menu");
 2242                key_context.add("showing_completions");
 2243            }
 2244            Some(CodeContextMenu::CodeActions(_)) => {
 2245                key_context.add("menu");
 2246                key_context.add("showing_code_actions")
 2247            }
 2248            None => {}
 2249        }
 2250
 2251        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2252        if !self.focus_handle(cx).contains_focused(window, cx)
 2253            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2254        {
 2255            for addon in self.addons.values() {
 2256                addon.extend_key_context(&mut key_context, cx)
 2257            }
 2258        }
 2259
 2260        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2261            if let Some(extension) = singleton_buffer
 2262                .read(cx)
 2263                .file()
 2264                .and_then(|file| file.path().extension()?.to_str())
 2265            {
 2266                key_context.set("extension", extension.to_string());
 2267            }
 2268        } else {
 2269            key_context.add("multibuffer");
 2270        }
 2271
 2272        if has_active_edit_prediction {
 2273            if self.edit_prediction_in_conflict() {
 2274                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2275            } else {
 2276                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2277                key_context.add("copilot_suggestion");
 2278            }
 2279        }
 2280
 2281        if self.selection_mark_mode {
 2282            key_context.add("selection_mode");
 2283        }
 2284
 2285        key_context
 2286    }
 2287
 2288    fn show_mouse_cursor(&mut self) {
 2289        self.mouse_cursor_hidden = false;
 2290    }
 2291
 2292    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2293        self.mouse_cursor_hidden = match origin {
 2294            HideMouseCursorOrigin::TypingAction => {
 2295                matches!(
 2296                    self.hide_mouse_mode,
 2297                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2298                )
 2299            }
 2300            HideMouseCursorOrigin::MovementAction => {
 2301                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2302            }
 2303        };
 2304    }
 2305
 2306    pub fn edit_prediction_in_conflict(&self) -> bool {
 2307        if !self.show_edit_predictions_in_menu() {
 2308            return false;
 2309        }
 2310
 2311        let showing_completions = self
 2312            .context_menu
 2313            .borrow()
 2314            .as_ref()
 2315            .map_or(false, |context| {
 2316                matches!(context, CodeContextMenu::Completions(_))
 2317            });
 2318
 2319        showing_completions
 2320            || self.edit_prediction_requires_modifier()
 2321            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2322            // bindings to insert tab characters.
 2323            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2324    }
 2325
 2326    pub fn accept_edit_prediction_keybind(
 2327        &self,
 2328        accept_partial: bool,
 2329        window: &Window,
 2330        cx: &App,
 2331    ) -> AcceptEditPredictionBinding {
 2332        let key_context = self.key_context_internal(true, window, cx);
 2333        let in_conflict = self.edit_prediction_in_conflict();
 2334
 2335        let bindings = if accept_partial {
 2336            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2337        } else {
 2338            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2339        };
 2340
 2341        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2342        // just the first one.
 2343        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2344            !in_conflict
 2345                || binding
 2346                    .keystrokes()
 2347                    .first()
 2348                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2349        }))
 2350    }
 2351
 2352    pub fn new_file(
 2353        workspace: &mut Workspace,
 2354        _: &workspace::NewFile,
 2355        window: &mut Window,
 2356        cx: &mut Context<Workspace>,
 2357    ) {
 2358        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2359            "Failed to create buffer",
 2360            window,
 2361            cx,
 2362            |e, _, _| match e.error_code() {
 2363                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2364                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2365                e.error_tag("required").unwrap_or("the latest version")
 2366            )),
 2367                _ => None,
 2368            },
 2369        );
 2370    }
 2371
 2372    pub fn new_in_workspace(
 2373        workspace: &mut Workspace,
 2374        window: &mut Window,
 2375        cx: &mut Context<Workspace>,
 2376    ) -> Task<Result<Entity<Editor>>> {
 2377        let project = workspace.project().clone();
 2378        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2379
 2380        cx.spawn_in(window, async move |workspace, cx| {
 2381            let buffer = create.await?;
 2382            workspace.update_in(cx, |workspace, window, cx| {
 2383                let editor =
 2384                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2385                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2386                editor
 2387            })
 2388        })
 2389    }
 2390
 2391    fn new_file_vertical(
 2392        workspace: &mut Workspace,
 2393        _: &workspace::NewFileSplitVertical,
 2394        window: &mut Window,
 2395        cx: &mut Context<Workspace>,
 2396    ) {
 2397        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2398    }
 2399
 2400    fn new_file_horizontal(
 2401        workspace: &mut Workspace,
 2402        _: &workspace::NewFileSplitHorizontal,
 2403        window: &mut Window,
 2404        cx: &mut Context<Workspace>,
 2405    ) {
 2406        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2407    }
 2408
 2409    fn new_file_in_direction(
 2410        workspace: &mut Workspace,
 2411        direction: SplitDirection,
 2412        window: &mut Window,
 2413        cx: &mut Context<Workspace>,
 2414    ) {
 2415        let project = workspace.project().clone();
 2416        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2417
 2418        cx.spawn_in(window, async move |workspace, cx| {
 2419            let buffer = create.await?;
 2420            workspace.update_in(cx, move |workspace, window, cx| {
 2421                workspace.split_item(
 2422                    direction,
 2423                    Box::new(
 2424                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2425                    ),
 2426                    window,
 2427                    cx,
 2428                )
 2429            })?;
 2430            anyhow::Ok(())
 2431        })
 2432        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2433            match e.error_code() {
 2434                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2435                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2436                e.error_tag("required").unwrap_or("the latest version")
 2437            )),
 2438                _ => None,
 2439            }
 2440        });
 2441    }
 2442
 2443    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2444        self.leader_id
 2445    }
 2446
 2447    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2448        &self.buffer
 2449    }
 2450
 2451    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2452        self.workspace.as_ref()?.0.upgrade()
 2453    }
 2454
 2455    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2456        self.buffer().read(cx).title(cx)
 2457    }
 2458
 2459    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2460        let git_blame_gutter_max_author_length = self
 2461            .render_git_blame_gutter(cx)
 2462            .then(|| {
 2463                if let Some(blame) = self.blame.as_ref() {
 2464                    let max_author_length =
 2465                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2466                    Some(max_author_length)
 2467                } else {
 2468                    None
 2469                }
 2470            })
 2471            .flatten();
 2472
 2473        EditorSnapshot {
 2474            mode: self.mode.clone(),
 2475            show_gutter: self.show_gutter,
 2476            show_line_numbers: self.show_line_numbers,
 2477            show_git_diff_gutter: self.show_git_diff_gutter,
 2478            show_code_actions: self.show_code_actions,
 2479            show_runnables: self.show_runnables,
 2480            show_breakpoints: self.show_breakpoints,
 2481            git_blame_gutter_max_author_length,
 2482            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2483            scroll_anchor: self.scroll_manager.anchor(),
 2484            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2485            placeholder_text: self.placeholder_text.clone(),
 2486            is_focused: self.focus_handle.is_focused(window),
 2487            current_line_highlight: self
 2488                .current_line_highlight
 2489                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2490            gutter_hovered: self.gutter_hovered,
 2491        }
 2492    }
 2493
 2494    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2495        self.buffer.read(cx).language_at(point, cx)
 2496    }
 2497
 2498    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2499        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2500    }
 2501
 2502    pub fn active_excerpt(
 2503        &self,
 2504        cx: &App,
 2505    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2506        self.buffer
 2507            .read(cx)
 2508            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2509    }
 2510
 2511    pub fn mode(&self) -> &EditorMode {
 2512        &self.mode
 2513    }
 2514
 2515    pub fn set_mode(&mut self, mode: EditorMode) {
 2516        self.mode = mode;
 2517    }
 2518
 2519    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2520        self.collaboration_hub.as_deref()
 2521    }
 2522
 2523    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2524        self.collaboration_hub = Some(hub);
 2525    }
 2526
 2527    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2528        self.in_project_search = in_project_search;
 2529    }
 2530
 2531    pub fn set_custom_context_menu(
 2532        &mut self,
 2533        f: impl 'static
 2534        + Fn(
 2535            &mut Self,
 2536            DisplayPoint,
 2537            &mut Window,
 2538            &mut Context<Self>,
 2539        ) -> Option<Entity<ui::ContextMenu>>,
 2540    ) {
 2541        self.custom_context_menu = Some(Box::new(f))
 2542    }
 2543
 2544    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2545        self.completion_provider = provider;
 2546    }
 2547
 2548    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2549        self.semantics_provider.clone()
 2550    }
 2551
 2552    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2553        self.semantics_provider = provider;
 2554    }
 2555
 2556    pub fn set_edit_prediction_provider<T>(
 2557        &mut self,
 2558        provider: Option<Entity<T>>,
 2559        window: &mut Window,
 2560        cx: &mut Context<Self>,
 2561    ) where
 2562        T: EditPredictionProvider,
 2563    {
 2564        self.edit_prediction_provider =
 2565            provider.map(|provider| RegisteredInlineCompletionProvider {
 2566                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2567                    if this.focus_handle.is_focused(window) {
 2568                        this.update_visible_inline_completion(window, cx);
 2569                    }
 2570                }),
 2571                provider: Arc::new(provider),
 2572            });
 2573        self.update_edit_prediction_settings(cx);
 2574        self.refresh_inline_completion(false, false, window, cx);
 2575    }
 2576
 2577    pub fn placeholder_text(&self) -> Option<&str> {
 2578        self.placeholder_text.as_deref()
 2579    }
 2580
 2581    pub fn set_placeholder_text(
 2582        &mut self,
 2583        placeholder_text: impl Into<Arc<str>>,
 2584        cx: &mut Context<Self>,
 2585    ) {
 2586        let placeholder_text = Some(placeholder_text.into());
 2587        if self.placeholder_text != placeholder_text {
 2588            self.placeholder_text = placeholder_text;
 2589            cx.notify();
 2590        }
 2591    }
 2592
 2593    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2594        self.cursor_shape = cursor_shape;
 2595
 2596        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2597        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2598
 2599        cx.notify();
 2600    }
 2601
 2602    pub fn set_current_line_highlight(
 2603        &mut self,
 2604        current_line_highlight: Option<CurrentLineHighlight>,
 2605    ) {
 2606        self.current_line_highlight = current_line_highlight;
 2607    }
 2608
 2609    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2610        self.collapse_matches = collapse_matches;
 2611    }
 2612
 2613    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2614        let buffers = self.buffer.read(cx).all_buffers();
 2615        let Some(project) = self.project.as_ref() else {
 2616            return;
 2617        };
 2618        project.update(cx, |project, cx| {
 2619            for buffer in buffers {
 2620                self.registered_buffers
 2621                    .entry(buffer.read(cx).remote_id())
 2622                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2623            }
 2624        })
 2625    }
 2626
 2627    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2628        if self.collapse_matches {
 2629            return range.start..range.start;
 2630        }
 2631        range.clone()
 2632    }
 2633
 2634    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2635        if self.display_map.read(cx).clip_at_line_ends != clip {
 2636            self.display_map
 2637                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2638        }
 2639    }
 2640
 2641    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2642        self.input_enabled = input_enabled;
 2643    }
 2644
 2645    pub fn set_inline_completions_hidden_for_vim_mode(
 2646        &mut self,
 2647        hidden: bool,
 2648        window: &mut Window,
 2649        cx: &mut Context<Self>,
 2650    ) {
 2651        if hidden != self.inline_completions_hidden_for_vim_mode {
 2652            self.inline_completions_hidden_for_vim_mode = hidden;
 2653            if hidden {
 2654                self.update_visible_inline_completion(window, cx);
 2655            } else {
 2656                self.refresh_inline_completion(true, false, window, cx);
 2657            }
 2658        }
 2659    }
 2660
 2661    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2662        self.menu_inline_completions_policy = value;
 2663    }
 2664
 2665    pub fn set_autoindent(&mut self, autoindent: bool) {
 2666        if autoindent {
 2667            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2668        } else {
 2669            self.autoindent_mode = None;
 2670        }
 2671    }
 2672
 2673    pub fn read_only(&self, cx: &App) -> bool {
 2674        self.read_only || self.buffer.read(cx).read_only()
 2675    }
 2676
 2677    pub fn set_read_only(&mut self, read_only: bool) {
 2678        self.read_only = read_only;
 2679    }
 2680
 2681    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2682        self.use_autoclose = autoclose;
 2683    }
 2684
 2685    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2686        self.use_auto_surround = auto_surround;
 2687    }
 2688
 2689    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2690        self.auto_replace_emoji_shortcode = auto_replace;
 2691    }
 2692
 2693    pub fn toggle_edit_predictions(
 2694        &mut self,
 2695        _: &ToggleEditPrediction,
 2696        window: &mut Window,
 2697        cx: &mut Context<Self>,
 2698    ) {
 2699        if self.show_inline_completions_override.is_some() {
 2700            self.set_show_edit_predictions(None, window, cx);
 2701        } else {
 2702            let show_edit_predictions = !self.edit_predictions_enabled();
 2703            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2704        }
 2705    }
 2706
 2707    pub fn set_show_edit_predictions(
 2708        &mut self,
 2709        show_edit_predictions: Option<bool>,
 2710        window: &mut Window,
 2711        cx: &mut Context<Self>,
 2712    ) {
 2713        self.show_inline_completions_override = show_edit_predictions;
 2714        self.update_edit_prediction_settings(cx);
 2715
 2716        if let Some(false) = show_edit_predictions {
 2717            self.discard_inline_completion(false, cx);
 2718        } else {
 2719            self.refresh_inline_completion(false, true, window, cx);
 2720        }
 2721    }
 2722
 2723    fn inline_completions_disabled_in_scope(
 2724        &self,
 2725        buffer: &Entity<Buffer>,
 2726        buffer_position: language::Anchor,
 2727        cx: &App,
 2728    ) -> bool {
 2729        let snapshot = buffer.read(cx).snapshot();
 2730        let settings = snapshot.settings_at(buffer_position, cx);
 2731
 2732        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2733            return false;
 2734        };
 2735
 2736        scope.override_name().map_or(false, |scope_name| {
 2737            settings
 2738                .edit_predictions_disabled_in
 2739                .iter()
 2740                .any(|s| s == scope_name)
 2741        })
 2742    }
 2743
 2744    pub fn set_use_modal_editing(&mut self, to: bool) {
 2745        self.use_modal_editing = to;
 2746    }
 2747
 2748    pub fn use_modal_editing(&self) -> bool {
 2749        self.use_modal_editing
 2750    }
 2751
 2752    fn selections_did_change(
 2753        &mut self,
 2754        local: bool,
 2755        old_cursor_position: &Anchor,
 2756        effects: SelectionEffects,
 2757        window: &mut Window,
 2758        cx: &mut Context<Self>,
 2759    ) {
 2760        window.invalidate_character_coordinates();
 2761
 2762        // Copy selections to primary selection buffer
 2763        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2764        if local {
 2765            let selections = self.selections.all::<usize>(cx);
 2766            let buffer_handle = self.buffer.read(cx).read(cx);
 2767
 2768            let mut text = String::new();
 2769            for (index, selection) in selections.iter().enumerate() {
 2770                let text_for_selection = buffer_handle
 2771                    .text_for_range(selection.start..selection.end)
 2772                    .collect::<String>();
 2773
 2774                text.push_str(&text_for_selection);
 2775                if index != selections.len() - 1 {
 2776                    text.push('\n');
 2777                }
 2778            }
 2779
 2780            if !text.is_empty() {
 2781                cx.write_to_primary(ClipboardItem::new_string(text));
 2782            }
 2783        }
 2784
 2785        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2786            self.buffer.update(cx, |buffer, cx| {
 2787                buffer.set_active_selections(
 2788                    &self.selections.disjoint_anchors(),
 2789                    self.selections.line_mode,
 2790                    self.cursor_shape,
 2791                    cx,
 2792                )
 2793            });
 2794        }
 2795        let display_map = self
 2796            .display_map
 2797            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2798        let buffer = &display_map.buffer_snapshot;
 2799        if self.selections.count() == 1 {
 2800            self.add_selections_state = None;
 2801        }
 2802        self.select_next_state = None;
 2803        self.select_prev_state = None;
 2804        self.select_syntax_node_history.try_clear();
 2805        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2806        self.snippet_stack
 2807            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2808        self.take_rename(false, window, cx);
 2809
 2810        let newest_selection = self.selections.newest_anchor();
 2811        let new_cursor_position = newest_selection.head();
 2812        let selection_start = newest_selection.start;
 2813
 2814        if effects.nav_history {
 2815            self.push_to_nav_history(
 2816                *old_cursor_position,
 2817                Some(new_cursor_position.to_point(buffer)),
 2818                false,
 2819                cx,
 2820            );
 2821        }
 2822
 2823        if local {
 2824            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2825                if !self.registered_buffers.contains_key(&buffer_id) {
 2826                    if let Some(project) = self.project.as_ref() {
 2827                        project.update(cx, |project, cx| {
 2828                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2829                                return;
 2830                            };
 2831                            self.registered_buffers.insert(
 2832                                buffer_id,
 2833                                project.register_buffer_with_language_servers(&buffer, cx),
 2834                            );
 2835                        })
 2836                    }
 2837                }
 2838            }
 2839
 2840            let mut context_menu = self.context_menu.borrow_mut();
 2841            let completion_menu = match context_menu.as_ref() {
 2842                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2843                Some(CodeContextMenu::CodeActions(_)) => {
 2844                    *context_menu = None;
 2845                    None
 2846                }
 2847                None => None,
 2848            };
 2849            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2850            drop(context_menu);
 2851
 2852            if effects.completions {
 2853                if let Some(completion_position) = completion_position {
 2854                    let start_offset = selection_start.to_offset(buffer);
 2855                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2856                    let continue_showing = if position_matches {
 2857                        if self.snippet_stack.is_empty() {
 2858                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2859                        } else {
 2860                            // Snippet choices can be shown even when the cursor is in whitespace.
 2861                            // Dismissing the menu when actions like backspace
 2862                            true
 2863                        }
 2864                    } else {
 2865                        false
 2866                    };
 2867
 2868                    if continue_showing {
 2869                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2870                    } else {
 2871                        self.hide_context_menu(window, cx);
 2872                    }
 2873                }
 2874            }
 2875
 2876            hide_hover(self, cx);
 2877
 2878            if old_cursor_position.to_display_point(&display_map).row()
 2879                != new_cursor_position.to_display_point(&display_map).row()
 2880            {
 2881                self.available_code_actions.take();
 2882            }
 2883            self.refresh_code_actions(window, cx);
 2884            self.refresh_document_highlights(cx);
 2885            self.refresh_selected_text_highlights(false, window, cx);
 2886            refresh_matching_bracket_highlights(self, window, cx);
 2887            self.update_visible_inline_completion(window, cx);
 2888            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2889            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2890            self.inline_blame_popover.take();
 2891            if self.git_blame_inline_enabled {
 2892                self.start_inline_blame_timer(window, cx);
 2893            }
 2894        }
 2895
 2896        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2897        cx.emit(EditorEvent::SelectionsChanged { local });
 2898
 2899        let selections = &self.selections.disjoint;
 2900        if selections.len() == 1 {
 2901            cx.emit(SearchEvent::ActiveMatchChanged)
 2902        }
 2903        if local {
 2904            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2905                let inmemory_selections = selections
 2906                    .iter()
 2907                    .map(|s| {
 2908                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2909                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2910                    })
 2911                    .collect();
 2912                self.update_restoration_data(cx, |data| {
 2913                    data.selections = inmemory_selections;
 2914                });
 2915
 2916                if WorkspaceSettings::get(None, cx).restore_on_startup
 2917                    != RestoreOnStartupBehavior::None
 2918                {
 2919                    if let Some(workspace_id) =
 2920                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2921                    {
 2922                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2923                        let selections = selections.clone();
 2924                        let background_executor = cx.background_executor().clone();
 2925                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2926                        self.serialize_selections = cx.background_spawn(async move {
 2927                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2928                    let db_selections = selections
 2929                        .iter()
 2930                        .map(|selection| {
 2931                            (
 2932                                selection.start.to_offset(&snapshot),
 2933                                selection.end.to_offset(&snapshot),
 2934                            )
 2935                        })
 2936                        .collect();
 2937
 2938                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2939                        .await
 2940                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2941                        .log_err();
 2942                });
 2943                    }
 2944                }
 2945            }
 2946        }
 2947
 2948        cx.notify();
 2949    }
 2950
 2951    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2952        use text::ToOffset as _;
 2953        use text::ToPoint as _;
 2954
 2955        if self.mode.is_minimap()
 2956            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2957        {
 2958            return;
 2959        }
 2960
 2961        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2962            return;
 2963        };
 2964
 2965        let snapshot = singleton.read(cx).snapshot();
 2966        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2967            let display_snapshot = display_map.snapshot(cx);
 2968
 2969            display_snapshot
 2970                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2971                .map(|fold| {
 2972                    fold.range.start.text_anchor.to_point(&snapshot)
 2973                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2974                })
 2975                .collect()
 2976        });
 2977        self.update_restoration_data(cx, |data| {
 2978            data.folds = inmemory_folds;
 2979        });
 2980
 2981        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2982            return;
 2983        };
 2984        let background_executor = cx.background_executor().clone();
 2985        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2986        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2987            display_map
 2988                .snapshot(cx)
 2989                .folds_in_range(0..snapshot.len())
 2990                .map(|fold| {
 2991                    (
 2992                        fold.range.start.text_anchor.to_offset(&snapshot),
 2993                        fold.range.end.text_anchor.to_offset(&snapshot),
 2994                    )
 2995                })
 2996                .collect()
 2997        });
 2998        self.serialize_folds = cx.background_spawn(async move {
 2999            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3000            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3001                .await
 3002                .with_context(|| {
 3003                    format!(
 3004                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3005                    )
 3006                })
 3007                .log_err();
 3008        });
 3009    }
 3010
 3011    pub fn sync_selections(
 3012        &mut self,
 3013        other: Entity<Editor>,
 3014        cx: &mut Context<Self>,
 3015    ) -> gpui::Subscription {
 3016        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3017        self.selections.change_with(cx, |selections| {
 3018            selections.select_anchors(other_selections);
 3019        });
 3020
 3021        let other_subscription =
 3022            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3023                EditorEvent::SelectionsChanged { local: true } => {
 3024                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3025                    if other_selections.is_empty() {
 3026                        return;
 3027                    }
 3028                    this.selections.change_with(cx, |selections| {
 3029                        selections.select_anchors(other_selections);
 3030                    });
 3031                }
 3032                _ => {}
 3033            });
 3034
 3035        let this_subscription =
 3036            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3037                EditorEvent::SelectionsChanged { local: true } => {
 3038                    let these_selections = this.selections.disjoint.to_vec();
 3039                    if these_selections.is_empty() {
 3040                        return;
 3041                    }
 3042                    other.update(cx, |other_editor, cx| {
 3043                        other_editor.selections.change_with(cx, |selections| {
 3044                            selections.select_anchors(these_selections);
 3045                        })
 3046                    });
 3047                }
 3048                _ => {}
 3049            });
 3050
 3051        Subscription::join(other_subscription, this_subscription)
 3052    }
 3053
 3054    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3055    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3056    /// effects of selection change occur at the end of the transaction.
 3057    pub fn change_selections<R>(
 3058        &mut self,
 3059        effects: impl Into<SelectionEffects>,
 3060        window: &mut Window,
 3061        cx: &mut Context<Self>,
 3062        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3063    ) -> R {
 3064        let effects = effects.into();
 3065        if let Some(state) = &mut self.deferred_selection_effects_state {
 3066            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3067            state.effects.completions = effects.completions;
 3068            state.effects.nav_history |= effects.nav_history;
 3069            let (changed, result) = self.selections.change_with(cx, change);
 3070            state.changed |= changed;
 3071            return result;
 3072        }
 3073        let mut state = DeferredSelectionEffectsState {
 3074            changed: false,
 3075            effects,
 3076            old_cursor_position: self.selections.newest_anchor().head(),
 3077            history_entry: SelectionHistoryEntry {
 3078                selections: self.selections.disjoint_anchors(),
 3079                select_next_state: self.select_next_state.clone(),
 3080                select_prev_state: self.select_prev_state.clone(),
 3081                add_selections_state: self.add_selections_state.clone(),
 3082            },
 3083        };
 3084        let (changed, result) = self.selections.change_with(cx, change);
 3085        state.changed = state.changed || changed;
 3086        if self.defer_selection_effects {
 3087            self.deferred_selection_effects_state = Some(state);
 3088        } else {
 3089            self.apply_selection_effects(state, window, cx);
 3090        }
 3091        result
 3092    }
 3093
 3094    /// Defers the effects of selection change, so that the effects of multiple calls to
 3095    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3096    /// to selection history and the state of popovers based on selection position aren't
 3097    /// erroneously updated.
 3098    pub fn with_selection_effects_deferred<R>(
 3099        &mut self,
 3100        window: &mut Window,
 3101        cx: &mut Context<Self>,
 3102        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3103    ) -> R {
 3104        let already_deferred = self.defer_selection_effects;
 3105        self.defer_selection_effects = true;
 3106        let result = update(self, window, cx);
 3107        if !already_deferred {
 3108            self.defer_selection_effects = false;
 3109            if let Some(state) = self.deferred_selection_effects_state.take() {
 3110                self.apply_selection_effects(state, window, cx);
 3111            }
 3112        }
 3113        result
 3114    }
 3115
 3116    fn apply_selection_effects(
 3117        &mut self,
 3118        state: DeferredSelectionEffectsState,
 3119        window: &mut Window,
 3120        cx: &mut Context<Self>,
 3121    ) {
 3122        if state.changed {
 3123            self.selection_history.push(state.history_entry);
 3124
 3125            if let Some(autoscroll) = state.effects.scroll {
 3126                self.request_autoscroll(autoscroll, cx);
 3127            }
 3128
 3129            let old_cursor_position = &state.old_cursor_position;
 3130
 3131            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3132
 3133            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3134                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3135            }
 3136        }
 3137    }
 3138
 3139    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3140    where
 3141        I: IntoIterator<Item = (Range<S>, T)>,
 3142        S: ToOffset,
 3143        T: Into<Arc<str>>,
 3144    {
 3145        if self.read_only(cx) {
 3146            return;
 3147        }
 3148
 3149        self.buffer
 3150            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3151    }
 3152
 3153    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3154    where
 3155        I: IntoIterator<Item = (Range<S>, T)>,
 3156        S: ToOffset,
 3157        T: Into<Arc<str>>,
 3158    {
 3159        if self.read_only(cx) {
 3160            return;
 3161        }
 3162
 3163        self.buffer.update(cx, |buffer, cx| {
 3164            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3165        });
 3166    }
 3167
 3168    pub fn edit_with_block_indent<I, S, T>(
 3169        &mut self,
 3170        edits: I,
 3171        original_indent_columns: Vec<Option<u32>>,
 3172        cx: &mut Context<Self>,
 3173    ) where
 3174        I: IntoIterator<Item = (Range<S>, T)>,
 3175        S: ToOffset,
 3176        T: Into<Arc<str>>,
 3177    {
 3178        if self.read_only(cx) {
 3179            return;
 3180        }
 3181
 3182        self.buffer.update(cx, |buffer, cx| {
 3183            buffer.edit(
 3184                edits,
 3185                Some(AutoindentMode::Block {
 3186                    original_indent_columns,
 3187                }),
 3188                cx,
 3189            )
 3190        });
 3191    }
 3192
 3193    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3194        self.hide_context_menu(window, cx);
 3195
 3196        match phase {
 3197            SelectPhase::Begin {
 3198                position,
 3199                add,
 3200                click_count,
 3201            } => self.begin_selection(position, add, click_count, window, cx),
 3202            SelectPhase::BeginColumnar {
 3203                position,
 3204                goal_column,
 3205                reset,
 3206            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3207            SelectPhase::Extend {
 3208                position,
 3209                click_count,
 3210            } => self.extend_selection(position, click_count, window, cx),
 3211            SelectPhase::Update {
 3212                position,
 3213                goal_column,
 3214                scroll_delta,
 3215            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3216            SelectPhase::End => self.end_selection(window, cx),
 3217        }
 3218    }
 3219
 3220    fn extend_selection(
 3221        &mut self,
 3222        position: DisplayPoint,
 3223        click_count: usize,
 3224        window: &mut Window,
 3225        cx: &mut Context<Self>,
 3226    ) {
 3227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3228        let tail = self.selections.newest::<usize>(cx).tail();
 3229        self.begin_selection(position, false, click_count, window, cx);
 3230
 3231        let position = position.to_offset(&display_map, Bias::Left);
 3232        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3233
 3234        let mut pending_selection = self
 3235            .selections
 3236            .pending_anchor()
 3237            .expect("extend_selection not called with pending selection");
 3238        if position >= tail {
 3239            pending_selection.start = tail_anchor;
 3240        } else {
 3241            pending_selection.end = tail_anchor;
 3242            pending_selection.reversed = true;
 3243        }
 3244
 3245        let mut pending_mode = self.selections.pending_mode().unwrap();
 3246        match &mut pending_mode {
 3247            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3248            _ => {}
 3249        }
 3250
 3251        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3252            SelectionEffects::scroll(Autoscroll::fit())
 3253        } else {
 3254            SelectionEffects::no_scroll()
 3255        };
 3256
 3257        self.change_selections(effects, window, cx, |s| {
 3258            s.set_pending(pending_selection, pending_mode)
 3259        });
 3260    }
 3261
 3262    fn begin_selection(
 3263        &mut self,
 3264        position: DisplayPoint,
 3265        add: bool,
 3266        click_count: usize,
 3267        window: &mut Window,
 3268        cx: &mut Context<Self>,
 3269    ) {
 3270        if !self.focus_handle.is_focused(window) {
 3271            self.last_focused_descendant = None;
 3272            window.focus(&self.focus_handle);
 3273        }
 3274
 3275        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3276        let buffer = &display_map.buffer_snapshot;
 3277        let position = display_map.clip_point(position, Bias::Left);
 3278
 3279        let start;
 3280        let end;
 3281        let mode;
 3282        let mut auto_scroll;
 3283        match click_count {
 3284            1 => {
 3285                start = buffer.anchor_before(position.to_point(&display_map));
 3286                end = start;
 3287                mode = SelectMode::Character;
 3288                auto_scroll = true;
 3289            }
 3290            2 => {
 3291                let range = movement::surrounding_word(&display_map, position);
 3292                start = buffer.anchor_before(range.start.to_point(&display_map));
 3293                end = buffer.anchor_before(range.end.to_point(&display_map));
 3294                mode = SelectMode::Word(start..end);
 3295                auto_scroll = true;
 3296            }
 3297            3 => {
 3298                let position = display_map
 3299                    .clip_point(position, Bias::Left)
 3300                    .to_point(&display_map);
 3301                let line_start = display_map.prev_line_boundary(position).0;
 3302                let next_line_start = buffer.clip_point(
 3303                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3304                    Bias::Left,
 3305                );
 3306                start = buffer.anchor_before(line_start);
 3307                end = buffer.anchor_before(next_line_start);
 3308                mode = SelectMode::Line(start..end);
 3309                auto_scroll = true;
 3310            }
 3311            _ => {
 3312                start = buffer.anchor_before(0);
 3313                end = buffer.anchor_before(buffer.len());
 3314                mode = SelectMode::All;
 3315                auto_scroll = false;
 3316            }
 3317        }
 3318        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3319
 3320        let point_to_delete: Option<usize> = {
 3321            let selected_points: Vec<Selection<Point>> =
 3322                self.selections.disjoint_in_range(start..end, cx);
 3323
 3324            if !add || click_count > 1 {
 3325                None
 3326            } else if !selected_points.is_empty() {
 3327                Some(selected_points[0].id)
 3328            } else {
 3329                let clicked_point_already_selected =
 3330                    self.selections.disjoint.iter().find(|selection| {
 3331                        selection.start.to_point(buffer) == start.to_point(buffer)
 3332                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3333                    });
 3334
 3335                clicked_point_already_selected.map(|selection| selection.id)
 3336            }
 3337        };
 3338
 3339        let selections_count = self.selections.count();
 3340
 3341        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3342            if let Some(point_to_delete) = point_to_delete {
 3343                s.delete(point_to_delete);
 3344
 3345                if selections_count == 1 {
 3346                    s.set_pending_anchor_range(start..end, mode);
 3347                }
 3348            } else {
 3349                if !add {
 3350                    s.clear_disjoint();
 3351                }
 3352
 3353                s.set_pending_anchor_range(start..end, mode);
 3354            }
 3355        });
 3356    }
 3357
 3358    fn begin_columnar_selection(
 3359        &mut self,
 3360        position: DisplayPoint,
 3361        goal_column: u32,
 3362        reset: bool,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365    ) {
 3366        if !self.focus_handle.is_focused(window) {
 3367            self.last_focused_descendant = None;
 3368            window.focus(&self.focus_handle);
 3369        }
 3370
 3371        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3372
 3373        if reset {
 3374            let pointer_position = display_map
 3375                .buffer_snapshot
 3376                .anchor_before(position.to_point(&display_map));
 3377
 3378            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3379                s.clear_disjoint();
 3380                s.set_pending_anchor_range(
 3381                    pointer_position..pointer_position,
 3382                    SelectMode::Character,
 3383                );
 3384            });
 3385            if position.column() != goal_column {
 3386                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3387            } else {
 3388                self.columnar_display_point = None;
 3389            }
 3390        }
 3391
 3392        let tail = self.selections.newest::<Point>(cx).tail();
 3393        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3394
 3395        if !reset {
 3396            self.columnar_display_point = None;
 3397            self.select_columns(
 3398                tail.to_display_point(&display_map),
 3399                position,
 3400                goal_column,
 3401                &display_map,
 3402                window,
 3403                cx,
 3404            );
 3405        }
 3406    }
 3407
 3408    fn update_selection(
 3409        &mut self,
 3410        position: DisplayPoint,
 3411        goal_column: u32,
 3412        scroll_delta: gpui::Point<f32>,
 3413        window: &mut Window,
 3414        cx: &mut Context<Self>,
 3415    ) {
 3416        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3417
 3418        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3419            let tail = self
 3420                .columnar_display_point
 3421                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3422            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3423        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3424            let buffer = self.buffer.read(cx).snapshot(cx);
 3425            let head;
 3426            let tail;
 3427            let mode = self.selections.pending_mode().unwrap();
 3428            match &mode {
 3429                SelectMode::Character => {
 3430                    head = position.to_point(&display_map);
 3431                    tail = pending.tail().to_point(&buffer);
 3432                }
 3433                SelectMode::Word(original_range) => {
 3434                    let original_display_range = original_range.start.to_display_point(&display_map)
 3435                        ..original_range.end.to_display_point(&display_map);
 3436                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3437                        ..original_display_range.end.to_point(&display_map);
 3438                    if movement::is_inside_word(&display_map, position)
 3439                        || original_display_range.contains(&position)
 3440                    {
 3441                        let word_range = movement::surrounding_word(&display_map, position);
 3442                        if word_range.start < original_display_range.start {
 3443                            head = word_range.start.to_point(&display_map);
 3444                        } else {
 3445                            head = word_range.end.to_point(&display_map);
 3446                        }
 3447                    } else {
 3448                        head = position.to_point(&display_map);
 3449                    }
 3450
 3451                    if head <= original_buffer_range.start {
 3452                        tail = original_buffer_range.end;
 3453                    } else {
 3454                        tail = original_buffer_range.start;
 3455                    }
 3456                }
 3457                SelectMode::Line(original_range) => {
 3458                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3459
 3460                    let position = display_map
 3461                        .clip_point(position, Bias::Left)
 3462                        .to_point(&display_map);
 3463                    let line_start = display_map.prev_line_boundary(position).0;
 3464                    let next_line_start = buffer.clip_point(
 3465                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3466                        Bias::Left,
 3467                    );
 3468
 3469                    if line_start < original_range.start {
 3470                        head = line_start
 3471                    } else {
 3472                        head = next_line_start
 3473                    }
 3474
 3475                    if head <= original_range.start {
 3476                        tail = original_range.end;
 3477                    } else {
 3478                        tail = original_range.start;
 3479                    }
 3480                }
 3481                SelectMode::All => {
 3482                    return;
 3483                }
 3484            };
 3485
 3486            if head < tail {
 3487                pending.start = buffer.anchor_before(head);
 3488                pending.end = buffer.anchor_before(tail);
 3489                pending.reversed = true;
 3490            } else {
 3491                pending.start = buffer.anchor_before(tail);
 3492                pending.end = buffer.anchor_before(head);
 3493                pending.reversed = false;
 3494            }
 3495
 3496            self.change_selections(None, window, cx, |s| {
 3497                s.set_pending(pending, mode);
 3498            });
 3499        } else {
 3500            log::error!("update_selection dispatched with no pending selection");
 3501            return;
 3502        }
 3503
 3504        self.apply_scroll_delta(scroll_delta, window, cx);
 3505        cx.notify();
 3506    }
 3507
 3508    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3509        self.columnar_selection_tail.take();
 3510        if self.selections.pending_anchor().is_some() {
 3511            let selections = self.selections.all::<usize>(cx);
 3512            self.change_selections(None, window, cx, |s| {
 3513                s.select(selections);
 3514                s.clear_pending();
 3515            });
 3516        }
 3517    }
 3518
 3519    fn select_columns(
 3520        &mut self,
 3521        tail: DisplayPoint,
 3522        head: DisplayPoint,
 3523        goal_column: u32,
 3524        display_map: &DisplaySnapshot,
 3525        window: &mut Window,
 3526        cx: &mut Context<Self>,
 3527    ) {
 3528        let start_row = cmp::min(tail.row(), head.row());
 3529        let end_row = cmp::max(tail.row(), head.row());
 3530        let start_column = cmp::min(tail.column(), goal_column);
 3531        let end_column = cmp::max(tail.column(), goal_column);
 3532        let reversed = start_column < tail.column();
 3533
 3534        let selection_ranges = (start_row.0..=end_row.0)
 3535            .map(DisplayRow)
 3536            .filter_map(|row| {
 3537                if !display_map.is_block_line(row) {
 3538                    let start = display_map
 3539                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3540                        .to_point(display_map);
 3541                    let end = display_map
 3542                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3543                        .to_point(display_map);
 3544                    if reversed {
 3545                        Some(end..start)
 3546                    } else {
 3547                        Some(start..end)
 3548                    }
 3549                } else {
 3550                    None
 3551                }
 3552            })
 3553            .collect::<Vec<_>>();
 3554
 3555        let mut non_empty_ranges = selection_ranges
 3556            .iter()
 3557            .filter(|selection_range| selection_range.start != selection_range.end)
 3558            .peekable();
 3559
 3560        let ranges = if non_empty_ranges.peek().is_some() {
 3561            non_empty_ranges.cloned().collect()
 3562        } else {
 3563            selection_ranges
 3564        };
 3565
 3566        self.change_selections(None, window, cx, |s| {
 3567            s.select_ranges(ranges);
 3568        });
 3569        cx.notify();
 3570    }
 3571
 3572    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3573        self.selections
 3574            .all_adjusted(cx)
 3575            .iter()
 3576            .any(|selection| !selection.is_empty())
 3577    }
 3578
 3579    pub fn has_pending_nonempty_selection(&self) -> bool {
 3580        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3581            Some(Selection { start, end, .. }) => start != end,
 3582            None => false,
 3583        };
 3584
 3585        pending_nonempty_selection
 3586            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3587    }
 3588
 3589    pub fn has_pending_selection(&self) -> bool {
 3590        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3591    }
 3592
 3593    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3594        self.selection_mark_mode = false;
 3595        self.selection_drag_state = SelectionDragState::None;
 3596
 3597        if self.clear_expanded_diff_hunks(cx) {
 3598            cx.notify();
 3599            return;
 3600        }
 3601        if self.dismiss_menus_and_popups(true, window, cx) {
 3602            return;
 3603        }
 3604
 3605        if self.mode.is_full()
 3606            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3607        {
 3608            return;
 3609        }
 3610
 3611        cx.propagate();
 3612    }
 3613
 3614    pub fn dismiss_menus_and_popups(
 3615        &mut self,
 3616        is_user_requested: bool,
 3617        window: &mut Window,
 3618        cx: &mut Context<Self>,
 3619    ) -> bool {
 3620        if self.take_rename(false, window, cx).is_some() {
 3621            return true;
 3622        }
 3623
 3624        if hide_hover(self, cx) {
 3625            return true;
 3626        }
 3627
 3628        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3629            return true;
 3630        }
 3631
 3632        if self.hide_context_menu(window, cx).is_some() {
 3633            return true;
 3634        }
 3635
 3636        if self.mouse_context_menu.take().is_some() {
 3637            return true;
 3638        }
 3639
 3640        if is_user_requested && self.discard_inline_completion(true, cx) {
 3641            return true;
 3642        }
 3643
 3644        if self.snippet_stack.pop().is_some() {
 3645            return true;
 3646        }
 3647
 3648        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3649            self.dismiss_diagnostics(cx);
 3650            return true;
 3651        }
 3652
 3653        false
 3654    }
 3655
 3656    fn linked_editing_ranges_for(
 3657        &self,
 3658        selection: Range<text::Anchor>,
 3659        cx: &App,
 3660    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3661        if self.linked_edit_ranges.is_empty() {
 3662            return None;
 3663        }
 3664        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3665            selection.end.buffer_id.and_then(|end_buffer_id| {
 3666                if selection.start.buffer_id != Some(end_buffer_id) {
 3667                    return None;
 3668                }
 3669                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3670                let snapshot = buffer.read(cx).snapshot();
 3671                self.linked_edit_ranges
 3672                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3673                    .map(|ranges| (ranges, snapshot, buffer))
 3674            })?;
 3675        use text::ToOffset as TO;
 3676        // find offset from the start of current range to current cursor position
 3677        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3678
 3679        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3680        let start_difference = start_offset - start_byte_offset;
 3681        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3682        let end_difference = end_offset - start_byte_offset;
 3683        // Current range has associated linked ranges.
 3684        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3685        for range in linked_ranges.iter() {
 3686            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3687            let end_offset = start_offset + end_difference;
 3688            let start_offset = start_offset + start_difference;
 3689            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3690                continue;
 3691            }
 3692            if self.selections.disjoint_anchor_ranges().any(|s| {
 3693                if s.start.buffer_id != selection.start.buffer_id
 3694                    || s.end.buffer_id != selection.end.buffer_id
 3695                {
 3696                    return false;
 3697                }
 3698                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3699                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3700            }) {
 3701                continue;
 3702            }
 3703            let start = buffer_snapshot.anchor_after(start_offset);
 3704            let end = buffer_snapshot.anchor_after(end_offset);
 3705            linked_edits
 3706                .entry(buffer.clone())
 3707                .or_default()
 3708                .push(start..end);
 3709        }
 3710        Some(linked_edits)
 3711    }
 3712
 3713    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3714        let text: Arc<str> = text.into();
 3715
 3716        if self.read_only(cx) {
 3717            return;
 3718        }
 3719
 3720        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3721
 3722        let selections = self.selections.all_adjusted(cx);
 3723        let mut bracket_inserted = false;
 3724        let mut edits = Vec::new();
 3725        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3726        let mut new_selections = Vec::with_capacity(selections.len());
 3727        let mut new_autoclose_regions = Vec::new();
 3728        let snapshot = self.buffer.read(cx).read(cx);
 3729        let mut clear_linked_edit_ranges = false;
 3730
 3731        for (selection, autoclose_region) in
 3732            self.selections_with_autoclose_regions(selections, &snapshot)
 3733        {
 3734            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3735                // Determine if the inserted text matches the opening or closing
 3736                // bracket of any of this language's bracket pairs.
 3737                let mut bracket_pair = None;
 3738                let mut is_bracket_pair_start = false;
 3739                let mut is_bracket_pair_end = false;
 3740                if !text.is_empty() {
 3741                    let mut bracket_pair_matching_end = None;
 3742                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3743                    //  and they are removing the character that triggered IME popup.
 3744                    for (pair, enabled) in scope.brackets() {
 3745                        if !pair.close && !pair.surround {
 3746                            continue;
 3747                        }
 3748
 3749                        if enabled && pair.start.ends_with(text.as_ref()) {
 3750                            let prefix_len = pair.start.len() - text.len();
 3751                            let preceding_text_matches_prefix = prefix_len == 0
 3752                                || (selection.start.column >= (prefix_len as u32)
 3753                                    && snapshot.contains_str_at(
 3754                                        Point::new(
 3755                                            selection.start.row,
 3756                                            selection.start.column - (prefix_len as u32),
 3757                                        ),
 3758                                        &pair.start[..prefix_len],
 3759                                    ));
 3760                            if preceding_text_matches_prefix {
 3761                                bracket_pair = Some(pair.clone());
 3762                                is_bracket_pair_start = true;
 3763                                break;
 3764                            }
 3765                        }
 3766                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3767                        {
 3768                            // take first bracket pair matching end, but don't break in case a later bracket
 3769                            // pair matches start
 3770                            bracket_pair_matching_end = Some(pair.clone());
 3771                        }
 3772                    }
 3773                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3774                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3775                        is_bracket_pair_end = true;
 3776                    }
 3777                }
 3778
 3779                if let Some(bracket_pair) = bracket_pair {
 3780                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3781                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3782                    let auto_surround =
 3783                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3784                    if selection.is_empty() {
 3785                        if is_bracket_pair_start {
 3786                            // If the inserted text is a suffix of an opening bracket and the
 3787                            // selection is preceded by the rest of the opening bracket, then
 3788                            // insert the closing bracket.
 3789                            let following_text_allows_autoclose = snapshot
 3790                                .chars_at(selection.start)
 3791                                .next()
 3792                                .map_or(true, |c| scope.should_autoclose_before(c));
 3793
 3794                            let preceding_text_allows_autoclose = selection.start.column == 0
 3795                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3796                                    true,
 3797                                    |c| {
 3798                                        bracket_pair.start != bracket_pair.end
 3799                                            || !snapshot
 3800                                                .char_classifier_at(selection.start)
 3801                                                .is_word(c)
 3802                                    },
 3803                                );
 3804
 3805                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3806                                && bracket_pair.start.len() == 1
 3807                            {
 3808                                let target = bracket_pair.start.chars().next().unwrap();
 3809                                let current_line_count = snapshot
 3810                                    .reversed_chars_at(selection.start)
 3811                                    .take_while(|&c| c != '\n')
 3812                                    .filter(|&c| c == target)
 3813                                    .count();
 3814                                current_line_count % 2 == 1
 3815                            } else {
 3816                                false
 3817                            };
 3818
 3819                            if autoclose
 3820                                && bracket_pair.close
 3821                                && following_text_allows_autoclose
 3822                                && preceding_text_allows_autoclose
 3823                                && !is_closing_quote
 3824                            {
 3825                                let anchor = snapshot.anchor_before(selection.end);
 3826                                new_selections.push((selection.map(|_| anchor), text.len()));
 3827                                new_autoclose_regions.push((
 3828                                    anchor,
 3829                                    text.len(),
 3830                                    selection.id,
 3831                                    bracket_pair.clone(),
 3832                                ));
 3833                                edits.push((
 3834                                    selection.range(),
 3835                                    format!("{}{}", text, bracket_pair.end).into(),
 3836                                ));
 3837                                bracket_inserted = true;
 3838                                continue;
 3839                            }
 3840                        }
 3841
 3842                        if let Some(region) = autoclose_region {
 3843                            // If the selection is followed by an auto-inserted closing bracket,
 3844                            // then don't insert that closing bracket again; just move the selection
 3845                            // past the closing bracket.
 3846                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3847                                && text.as_ref() == region.pair.end.as_str();
 3848                            if should_skip {
 3849                                let anchor = snapshot.anchor_after(selection.end);
 3850                                new_selections
 3851                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3852                                continue;
 3853                            }
 3854                        }
 3855
 3856                        let always_treat_brackets_as_autoclosed = snapshot
 3857                            .language_settings_at(selection.start, cx)
 3858                            .always_treat_brackets_as_autoclosed;
 3859                        if always_treat_brackets_as_autoclosed
 3860                            && is_bracket_pair_end
 3861                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3862                        {
 3863                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3864                            // and the inserted text is a closing bracket and the selection is followed
 3865                            // by the closing bracket then move the selection past the closing bracket.
 3866                            let anchor = snapshot.anchor_after(selection.end);
 3867                            new_selections.push((selection.map(|_| anchor), text.len()));
 3868                            continue;
 3869                        }
 3870                    }
 3871                    // If an opening bracket is 1 character long and is typed while
 3872                    // text is selected, then surround that text with the bracket pair.
 3873                    else if auto_surround
 3874                        && bracket_pair.surround
 3875                        && is_bracket_pair_start
 3876                        && bracket_pair.start.chars().count() == 1
 3877                    {
 3878                        edits.push((selection.start..selection.start, text.clone()));
 3879                        edits.push((
 3880                            selection.end..selection.end,
 3881                            bracket_pair.end.as_str().into(),
 3882                        ));
 3883                        bracket_inserted = true;
 3884                        new_selections.push((
 3885                            Selection {
 3886                                id: selection.id,
 3887                                start: snapshot.anchor_after(selection.start),
 3888                                end: snapshot.anchor_before(selection.end),
 3889                                reversed: selection.reversed,
 3890                                goal: selection.goal,
 3891                            },
 3892                            0,
 3893                        ));
 3894                        continue;
 3895                    }
 3896                }
 3897            }
 3898
 3899            if self.auto_replace_emoji_shortcode
 3900                && selection.is_empty()
 3901                && text.as_ref().ends_with(':')
 3902            {
 3903                if let Some(possible_emoji_short_code) =
 3904                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3905                {
 3906                    if !possible_emoji_short_code.is_empty() {
 3907                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3908                            let emoji_shortcode_start = Point::new(
 3909                                selection.start.row,
 3910                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3911                            );
 3912
 3913                            // Remove shortcode from buffer
 3914                            edits.push((
 3915                                emoji_shortcode_start..selection.start,
 3916                                "".to_string().into(),
 3917                            ));
 3918                            new_selections.push((
 3919                                Selection {
 3920                                    id: selection.id,
 3921                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3922                                    end: snapshot.anchor_before(selection.start),
 3923                                    reversed: selection.reversed,
 3924                                    goal: selection.goal,
 3925                                },
 3926                                0,
 3927                            ));
 3928
 3929                            // Insert emoji
 3930                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3931                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3932                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3933
 3934                            continue;
 3935                        }
 3936                    }
 3937                }
 3938            }
 3939
 3940            // If not handling any auto-close operation, then just replace the selected
 3941            // text with the given input and move the selection to the end of the
 3942            // newly inserted text.
 3943            let anchor = snapshot.anchor_after(selection.end);
 3944            if !self.linked_edit_ranges.is_empty() {
 3945                let start_anchor = snapshot.anchor_before(selection.start);
 3946
 3947                let is_word_char = text.chars().next().map_or(true, |char| {
 3948                    let classifier = snapshot
 3949                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3950                        .ignore_punctuation(true);
 3951                    classifier.is_word(char)
 3952                });
 3953
 3954                if is_word_char {
 3955                    if let Some(ranges) = self
 3956                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3957                    {
 3958                        for (buffer, edits) in ranges {
 3959                            linked_edits
 3960                                .entry(buffer.clone())
 3961                                .or_default()
 3962                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3963                        }
 3964                    }
 3965                } else {
 3966                    clear_linked_edit_ranges = true;
 3967                }
 3968            }
 3969
 3970            new_selections.push((selection.map(|_| anchor), 0));
 3971            edits.push((selection.start..selection.end, text.clone()));
 3972        }
 3973
 3974        drop(snapshot);
 3975
 3976        self.transact(window, cx, |this, window, cx| {
 3977            if clear_linked_edit_ranges {
 3978                this.linked_edit_ranges.clear();
 3979            }
 3980            let initial_buffer_versions =
 3981                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3982
 3983            this.buffer.update(cx, |buffer, cx| {
 3984                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3985            });
 3986            for (buffer, edits) in linked_edits {
 3987                buffer.update(cx, |buffer, cx| {
 3988                    let snapshot = buffer.snapshot();
 3989                    let edits = edits
 3990                        .into_iter()
 3991                        .map(|(range, text)| {
 3992                            use text::ToPoint as TP;
 3993                            let end_point = TP::to_point(&range.end, &snapshot);
 3994                            let start_point = TP::to_point(&range.start, &snapshot);
 3995                            (start_point..end_point, text)
 3996                        })
 3997                        .sorted_by_key(|(range, _)| range.start);
 3998                    buffer.edit(edits, None, cx);
 3999                })
 4000            }
 4001            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4002            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4003            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4004            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4005                .zip(new_selection_deltas)
 4006                .map(|(selection, delta)| Selection {
 4007                    id: selection.id,
 4008                    start: selection.start + delta,
 4009                    end: selection.end + delta,
 4010                    reversed: selection.reversed,
 4011                    goal: SelectionGoal::None,
 4012                })
 4013                .collect::<Vec<_>>();
 4014
 4015            let mut i = 0;
 4016            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4017                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4018                let start = map.buffer_snapshot.anchor_before(position);
 4019                let end = map.buffer_snapshot.anchor_after(position);
 4020                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4021                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4022                        Ordering::Less => i += 1,
 4023                        Ordering::Greater => break,
 4024                        Ordering::Equal => {
 4025                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4026                                Ordering::Less => i += 1,
 4027                                Ordering::Equal => break,
 4028                                Ordering::Greater => break,
 4029                            }
 4030                        }
 4031                    }
 4032                }
 4033                this.autoclose_regions.insert(
 4034                    i,
 4035                    AutocloseRegion {
 4036                        selection_id,
 4037                        range: start..end,
 4038                        pair,
 4039                    },
 4040                );
 4041            }
 4042
 4043            let had_active_inline_completion = this.has_active_inline_completion();
 4044            this.change_selections(
 4045                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4046                window,
 4047                cx,
 4048                |s| s.select(new_selections),
 4049            );
 4050
 4051            if !bracket_inserted {
 4052                if let Some(on_type_format_task) =
 4053                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4054                {
 4055                    on_type_format_task.detach_and_log_err(cx);
 4056                }
 4057            }
 4058
 4059            let editor_settings = EditorSettings::get_global(cx);
 4060            if bracket_inserted
 4061                && (editor_settings.auto_signature_help
 4062                    || editor_settings.show_signature_help_after_edits)
 4063            {
 4064                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4065            }
 4066
 4067            let trigger_in_words =
 4068                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4069            if this.hard_wrap.is_some() {
 4070                let latest: Range<Point> = this.selections.newest(cx).range();
 4071                if latest.is_empty()
 4072                    && this
 4073                        .buffer()
 4074                        .read(cx)
 4075                        .snapshot(cx)
 4076                        .line_len(MultiBufferRow(latest.start.row))
 4077                        == latest.start.column
 4078                {
 4079                    this.rewrap_impl(
 4080                        RewrapOptions {
 4081                            override_language_settings: true,
 4082                            preserve_existing_whitespace: true,
 4083                        },
 4084                        cx,
 4085                    )
 4086                }
 4087            }
 4088            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4089            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4090            this.refresh_inline_completion(true, false, window, cx);
 4091            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4092        });
 4093    }
 4094
 4095    fn find_possible_emoji_shortcode_at_position(
 4096        snapshot: &MultiBufferSnapshot,
 4097        position: Point,
 4098    ) -> Option<String> {
 4099        let mut chars = Vec::new();
 4100        let mut found_colon = false;
 4101        for char in snapshot.reversed_chars_at(position).take(100) {
 4102            // Found a possible emoji shortcode in the middle of the buffer
 4103            if found_colon {
 4104                if char.is_whitespace() {
 4105                    chars.reverse();
 4106                    return Some(chars.iter().collect());
 4107                }
 4108                // If the previous character is not a whitespace, we are in the middle of a word
 4109                // and we only want to complete the shortcode if the word is made up of other emojis
 4110                let mut containing_word = String::new();
 4111                for ch in snapshot
 4112                    .reversed_chars_at(position)
 4113                    .skip(chars.len() + 1)
 4114                    .take(100)
 4115                {
 4116                    if ch.is_whitespace() {
 4117                        break;
 4118                    }
 4119                    containing_word.push(ch);
 4120                }
 4121                let containing_word = containing_word.chars().rev().collect::<String>();
 4122                if util::word_consists_of_emojis(containing_word.as_str()) {
 4123                    chars.reverse();
 4124                    return Some(chars.iter().collect());
 4125                }
 4126            }
 4127
 4128            if char.is_whitespace() || !char.is_ascii() {
 4129                return None;
 4130            }
 4131            if char == ':' {
 4132                found_colon = true;
 4133            } else {
 4134                chars.push(char);
 4135            }
 4136        }
 4137        // Found a possible emoji shortcode at the beginning of the buffer
 4138        chars.reverse();
 4139        Some(chars.iter().collect())
 4140    }
 4141
 4142    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4143        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4144        self.transact(window, cx, |this, window, cx| {
 4145            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4146                let selections = this.selections.all::<usize>(cx);
 4147                let multi_buffer = this.buffer.read(cx);
 4148                let buffer = multi_buffer.snapshot(cx);
 4149                selections
 4150                    .iter()
 4151                    .map(|selection| {
 4152                        let start_point = selection.start.to_point(&buffer);
 4153                        let mut existing_indent =
 4154                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4155                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4156                        let start = selection.start;
 4157                        let end = selection.end;
 4158                        let selection_is_empty = start == end;
 4159                        let language_scope = buffer.language_scope_at(start);
 4160                        let (
 4161                            comment_delimiter,
 4162                            doc_delimiter,
 4163                            insert_extra_newline,
 4164                            indent_on_newline,
 4165                            indent_on_extra_newline,
 4166                        ) = if let Some(language) = &language_scope {
 4167                            let mut insert_extra_newline =
 4168                                insert_extra_newline_brackets(&buffer, start..end, language)
 4169                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4170
 4171                            // Comment extension on newline is allowed only for cursor selections
 4172                            let comment_delimiter = maybe!({
 4173                                if !selection_is_empty {
 4174                                    return None;
 4175                                }
 4176
 4177                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4178                                    return None;
 4179                                }
 4180
 4181                                let delimiters = language.line_comment_prefixes();
 4182                                let max_len_of_delimiter =
 4183                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4184                                let (snapshot, range) =
 4185                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4186
 4187                                let num_of_whitespaces = snapshot
 4188                                    .chars_for_range(range.clone())
 4189                                    .take_while(|c| c.is_whitespace())
 4190                                    .count();
 4191                                let comment_candidate = snapshot
 4192                                    .chars_for_range(range)
 4193                                    .skip(num_of_whitespaces)
 4194                                    .take(max_len_of_delimiter)
 4195                                    .collect::<String>();
 4196                                let (delimiter, trimmed_len) = delimiters
 4197                                    .iter()
 4198                                    .filter_map(|delimiter| {
 4199                                        let prefix = delimiter.trim_end();
 4200                                        if comment_candidate.starts_with(prefix) {
 4201                                            Some((delimiter, prefix.len()))
 4202                                        } else {
 4203                                            None
 4204                                        }
 4205                                    })
 4206                                    .max_by_key(|(_, len)| *len)?;
 4207
 4208                                let cursor_is_placed_after_comment_marker =
 4209                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4210                                if cursor_is_placed_after_comment_marker {
 4211                                    Some(delimiter.clone())
 4212                                } else {
 4213                                    None
 4214                                }
 4215                            });
 4216
 4217                            let mut indent_on_newline = IndentSize::spaces(0);
 4218                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4219
 4220                            let doc_delimiter = maybe!({
 4221                                if !selection_is_empty {
 4222                                    return None;
 4223                                }
 4224
 4225                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4226                                    return None;
 4227                                }
 4228
 4229                                let DocumentationConfig {
 4230                                    start: start_tag,
 4231                                    end: end_tag,
 4232                                    prefix: delimiter,
 4233                                    tab_size: len,
 4234                                } = language.documentation()?;
 4235
 4236                                let is_within_block_comment = buffer
 4237                                    .language_scope_at(start_point)
 4238                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4239                                if !is_within_block_comment {
 4240                                    return None;
 4241                                }
 4242
 4243                                let (snapshot, range) =
 4244                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4245
 4246                                let num_of_whitespaces = snapshot
 4247                                    .chars_for_range(range.clone())
 4248                                    .take_while(|c| c.is_whitespace())
 4249                                    .count();
 4250
 4251                                // 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.
 4252                                let column = start_point.column;
 4253                                let cursor_is_after_start_tag = {
 4254                                    let start_tag_len = start_tag.len();
 4255                                    let start_tag_line = snapshot
 4256                                        .chars_for_range(range.clone())
 4257                                        .skip(num_of_whitespaces)
 4258                                        .take(start_tag_len)
 4259                                        .collect::<String>();
 4260                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4261                                        num_of_whitespaces + start_tag_len <= column as usize
 4262                                    } else {
 4263                                        false
 4264                                    }
 4265                                };
 4266
 4267                                let cursor_is_after_delimiter = {
 4268                                    let delimiter_trim = delimiter.trim_end();
 4269                                    let delimiter_line = snapshot
 4270                                        .chars_for_range(range.clone())
 4271                                        .skip(num_of_whitespaces)
 4272                                        .take(delimiter_trim.len())
 4273                                        .collect::<String>();
 4274                                    if delimiter_line.starts_with(delimiter_trim) {
 4275                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4276                                    } else {
 4277                                        false
 4278                                    }
 4279                                };
 4280
 4281                                let cursor_is_before_end_tag_if_exists = {
 4282                                    let mut char_position = 0u32;
 4283                                    let mut end_tag_offset = None;
 4284
 4285                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4286                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4287                                            let chars_before_match =
 4288                                                chunk[..byte_pos].chars().count() as u32;
 4289                                            end_tag_offset =
 4290                                                Some(char_position + chars_before_match);
 4291                                            break 'outer;
 4292                                        }
 4293                                        char_position += chunk.chars().count() as u32;
 4294                                    }
 4295
 4296                                    if let Some(end_tag_offset) = end_tag_offset {
 4297                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4298                                        if cursor_is_after_start_tag {
 4299                                            if cursor_is_before_end_tag {
 4300                                                insert_extra_newline = true;
 4301                                            }
 4302                                            let cursor_is_at_start_of_end_tag =
 4303                                                column == end_tag_offset;
 4304                                            if cursor_is_at_start_of_end_tag {
 4305                                                indent_on_extra_newline.len = (*len).into();
 4306                                            }
 4307                                        }
 4308                                        cursor_is_before_end_tag
 4309                                    } else {
 4310                                        true
 4311                                    }
 4312                                };
 4313
 4314                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4315                                    && cursor_is_before_end_tag_if_exists
 4316                                {
 4317                                    if cursor_is_after_start_tag {
 4318                                        indent_on_newline.len = (*len).into();
 4319                                    }
 4320                                    Some(delimiter.clone())
 4321                                } else {
 4322                                    None
 4323                                }
 4324                            });
 4325
 4326                            (
 4327                                comment_delimiter,
 4328                                doc_delimiter,
 4329                                insert_extra_newline,
 4330                                indent_on_newline,
 4331                                indent_on_extra_newline,
 4332                            )
 4333                        } else {
 4334                            (
 4335                                None,
 4336                                None,
 4337                                false,
 4338                                IndentSize::default(),
 4339                                IndentSize::default(),
 4340                            )
 4341                        };
 4342
 4343                        let prevent_auto_indent = doc_delimiter.is_some();
 4344                        let delimiter = comment_delimiter.or(doc_delimiter);
 4345
 4346                        let capacity_for_delimiter =
 4347                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4348                        let mut new_text = String::with_capacity(
 4349                            1 + capacity_for_delimiter
 4350                                + existing_indent.len as usize
 4351                                + indent_on_newline.len as usize
 4352                                + indent_on_extra_newline.len as usize,
 4353                        );
 4354                        new_text.push('\n');
 4355                        new_text.extend(existing_indent.chars());
 4356                        new_text.extend(indent_on_newline.chars());
 4357
 4358                        if let Some(delimiter) = &delimiter {
 4359                            new_text.push_str(delimiter);
 4360                        }
 4361
 4362                        if insert_extra_newline {
 4363                            new_text.push('\n');
 4364                            new_text.extend(existing_indent.chars());
 4365                            new_text.extend(indent_on_extra_newline.chars());
 4366                        }
 4367
 4368                        let anchor = buffer.anchor_after(end);
 4369                        let new_selection = selection.map(|_| anchor);
 4370                        (
 4371                            ((start..end, new_text), prevent_auto_indent),
 4372                            (insert_extra_newline, new_selection),
 4373                        )
 4374                    })
 4375                    .unzip()
 4376            };
 4377
 4378            let mut auto_indent_edits = Vec::new();
 4379            let mut edits = Vec::new();
 4380            for (edit, prevent_auto_indent) in edits_with_flags {
 4381                if prevent_auto_indent {
 4382                    edits.push(edit);
 4383                } else {
 4384                    auto_indent_edits.push(edit);
 4385                }
 4386            }
 4387            if !edits.is_empty() {
 4388                this.edit(edits, cx);
 4389            }
 4390            if !auto_indent_edits.is_empty() {
 4391                this.edit_with_autoindent(auto_indent_edits, cx);
 4392            }
 4393
 4394            let buffer = this.buffer.read(cx).snapshot(cx);
 4395            let new_selections = selection_info
 4396                .into_iter()
 4397                .map(|(extra_newline_inserted, new_selection)| {
 4398                    let mut cursor = new_selection.end.to_point(&buffer);
 4399                    if extra_newline_inserted {
 4400                        cursor.row -= 1;
 4401                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4402                    }
 4403                    new_selection.map(|_| cursor)
 4404                })
 4405                .collect();
 4406
 4407            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4408                s.select(new_selections)
 4409            });
 4410            this.refresh_inline_completion(true, false, window, cx);
 4411        });
 4412    }
 4413
 4414    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4415        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4416
 4417        let buffer = self.buffer.read(cx);
 4418        let snapshot = buffer.snapshot(cx);
 4419
 4420        let mut edits = Vec::new();
 4421        let mut rows = Vec::new();
 4422
 4423        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4424            let cursor = selection.head();
 4425            let row = cursor.row;
 4426
 4427            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4428
 4429            let newline = "\n".to_string();
 4430            edits.push((start_of_line..start_of_line, newline));
 4431
 4432            rows.push(row + rows_inserted as u32);
 4433        }
 4434
 4435        self.transact(window, cx, |editor, window, cx| {
 4436            editor.edit(edits, cx);
 4437
 4438            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4439                let mut index = 0;
 4440                s.move_cursors_with(|map, _, _| {
 4441                    let row = rows[index];
 4442                    index += 1;
 4443
 4444                    let point = Point::new(row, 0);
 4445                    let boundary = map.next_line_boundary(point).1;
 4446                    let clipped = map.clip_point(boundary, Bias::Left);
 4447
 4448                    (clipped, SelectionGoal::None)
 4449                });
 4450            });
 4451
 4452            let mut indent_edits = Vec::new();
 4453            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4454            for row in rows {
 4455                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4456                for (row, indent) in indents {
 4457                    if indent.len == 0 {
 4458                        continue;
 4459                    }
 4460
 4461                    let text = match indent.kind {
 4462                        IndentKind::Space => " ".repeat(indent.len as usize),
 4463                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4464                    };
 4465                    let point = Point::new(row.0, 0);
 4466                    indent_edits.push((point..point, text));
 4467                }
 4468            }
 4469            editor.edit(indent_edits, cx);
 4470        });
 4471    }
 4472
 4473    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4474        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4475
 4476        let buffer = self.buffer.read(cx);
 4477        let snapshot = buffer.snapshot(cx);
 4478
 4479        let mut edits = Vec::new();
 4480        let mut rows = Vec::new();
 4481        let mut rows_inserted = 0;
 4482
 4483        for selection in self.selections.all_adjusted(cx) {
 4484            let cursor = selection.head();
 4485            let row = cursor.row;
 4486
 4487            let point = Point::new(row + 1, 0);
 4488            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4489
 4490            let newline = "\n".to_string();
 4491            edits.push((start_of_line..start_of_line, newline));
 4492
 4493            rows_inserted += 1;
 4494            rows.push(row + rows_inserted);
 4495        }
 4496
 4497        self.transact(window, cx, |editor, window, cx| {
 4498            editor.edit(edits, cx);
 4499
 4500            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4501                let mut index = 0;
 4502                s.move_cursors_with(|map, _, _| {
 4503                    let row = rows[index];
 4504                    index += 1;
 4505
 4506                    let point = Point::new(row, 0);
 4507                    let boundary = map.next_line_boundary(point).1;
 4508                    let clipped = map.clip_point(boundary, Bias::Left);
 4509
 4510                    (clipped, SelectionGoal::None)
 4511                });
 4512            });
 4513
 4514            let mut indent_edits = Vec::new();
 4515            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4516            for row in rows {
 4517                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4518                for (row, indent) in indents {
 4519                    if indent.len == 0 {
 4520                        continue;
 4521                    }
 4522
 4523                    let text = match indent.kind {
 4524                        IndentKind::Space => " ".repeat(indent.len as usize),
 4525                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4526                    };
 4527                    let point = Point::new(row.0, 0);
 4528                    indent_edits.push((point..point, text));
 4529                }
 4530            }
 4531            editor.edit(indent_edits, cx);
 4532        });
 4533    }
 4534
 4535    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4536        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4537            original_indent_columns: Vec::new(),
 4538        });
 4539        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4540    }
 4541
 4542    fn insert_with_autoindent_mode(
 4543        &mut self,
 4544        text: &str,
 4545        autoindent_mode: Option<AutoindentMode>,
 4546        window: &mut Window,
 4547        cx: &mut Context<Self>,
 4548    ) {
 4549        if self.read_only(cx) {
 4550            return;
 4551        }
 4552
 4553        let text: Arc<str> = text.into();
 4554        self.transact(window, cx, |this, window, cx| {
 4555            let old_selections = this.selections.all_adjusted(cx);
 4556            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4557                let anchors = {
 4558                    let snapshot = buffer.read(cx);
 4559                    old_selections
 4560                        .iter()
 4561                        .map(|s| {
 4562                            let anchor = snapshot.anchor_after(s.head());
 4563                            s.map(|_| anchor)
 4564                        })
 4565                        .collect::<Vec<_>>()
 4566                };
 4567                buffer.edit(
 4568                    old_selections
 4569                        .iter()
 4570                        .map(|s| (s.start..s.end, text.clone())),
 4571                    autoindent_mode,
 4572                    cx,
 4573                );
 4574                anchors
 4575            });
 4576
 4577            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4578                s.select_anchors(selection_anchors);
 4579            });
 4580
 4581            cx.notify();
 4582        });
 4583    }
 4584
 4585    fn trigger_completion_on_input(
 4586        &mut self,
 4587        text: &str,
 4588        trigger_in_words: bool,
 4589        window: &mut Window,
 4590        cx: &mut Context<Self>,
 4591    ) {
 4592        let completions_source = self
 4593            .context_menu
 4594            .borrow()
 4595            .as_ref()
 4596            .and_then(|menu| match menu {
 4597                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4598                CodeContextMenu::CodeActions(_) => None,
 4599            });
 4600
 4601        match completions_source {
 4602            Some(CompletionsMenuSource::Words) => {
 4603                self.show_word_completions(&ShowWordCompletions, window, cx)
 4604            }
 4605            Some(CompletionsMenuSource::Normal)
 4606            | Some(CompletionsMenuSource::SnippetChoices)
 4607            | None
 4608                if self.is_completion_trigger(
 4609                    text,
 4610                    trigger_in_words,
 4611                    completions_source.is_some(),
 4612                    cx,
 4613                ) =>
 4614            {
 4615                self.show_completions(
 4616                    &ShowCompletions {
 4617                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4618                    },
 4619                    window,
 4620                    cx,
 4621                )
 4622            }
 4623            _ => {
 4624                self.hide_context_menu(window, cx);
 4625            }
 4626        }
 4627    }
 4628
 4629    fn is_completion_trigger(
 4630        &self,
 4631        text: &str,
 4632        trigger_in_words: bool,
 4633        menu_is_open: bool,
 4634        cx: &mut Context<Self>,
 4635    ) -> bool {
 4636        let position = self.selections.newest_anchor().head();
 4637        let multibuffer = self.buffer.read(cx);
 4638        let Some(buffer) = position
 4639            .buffer_id
 4640            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4641        else {
 4642            return false;
 4643        };
 4644
 4645        if let Some(completion_provider) = &self.completion_provider {
 4646            completion_provider.is_completion_trigger(
 4647                &buffer,
 4648                position.text_anchor,
 4649                text,
 4650                trigger_in_words,
 4651                menu_is_open,
 4652                cx,
 4653            )
 4654        } else {
 4655            false
 4656        }
 4657    }
 4658
 4659    /// If any empty selections is touching the start of its innermost containing autoclose
 4660    /// region, expand it to select the brackets.
 4661    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4662        let selections = self.selections.all::<usize>(cx);
 4663        let buffer = self.buffer.read(cx).read(cx);
 4664        let new_selections = self
 4665            .selections_with_autoclose_regions(selections, &buffer)
 4666            .map(|(mut selection, region)| {
 4667                if !selection.is_empty() {
 4668                    return selection;
 4669                }
 4670
 4671                if let Some(region) = region {
 4672                    let mut range = region.range.to_offset(&buffer);
 4673                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4674                        range.start -= region.pair.start.len();
 4675                        if buffer.contains_str_at(range.start, &region.pair.start)
 4676                            && buffer.contains_str_at(range.end, &region.pair.end)
 4677                        {
 4678                            range.end += region.pair.end.len();
 4679                            selection.start = range.start;
 4680                            selection.end = range.end;
 4681
 4682                            return selection;
 4683                        }
 4684                    }
 4685                }
 4686
 4687                let always_treat_brackets_as_autoclosed = buffer
 4688                    .language_settings_at(selection.start, cx)
 4689                    .always_treat_brackets_as_autoclosed;
 4690
 4691                if !always_treat_brackets_as_autoclosed {
 4692                    return selection;
 4693                }
 4694
 4695                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4696                    for (pair, enabled) in scope.brackets() {
 4697                        if !enabled || !pair.close {
 4698                            continue;
 4699                        }
 4700
 4701                        if buffer.contains_str_at(selection.start, &pair.end) {
 4702                            let pair_start_len = pair.start.len();
 4703                            if buffer.contains_str_at(
 4704                                selection.start.saturating_sub(pair_start_len),
 4705                                &pair.start,
 4706                            ) {
 4707                                selection.start -= pair_start_len;
 4708                                selection.end += pair.end.len();
 4709
 4710                                return selection;
 4711                            }
 4712                        }
 4713                    }
 4714                }
 4715
 4716                selection
 4717            })
 4718            .collect();
 4719
 4720        drop(buffer);
 4721        self.change_selections(None, window, cx, |selections| {
 4722            selections.select(new_selections)
 4723        });
 4724    }
 4725
 4726    /// Iterate the given selections, and for each one, find the smallest surrounding
 4727    /// autoclose region. This uses the ordering of the selections and the autoclose
 4728    /// regions to avoid repeated comparisons.
 4729    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4730        &'a self,
 4731        selections: impl IntoIterator<Item = Selection<D>>,
 4732        buffer: &'a MultiBufferSnapshot,
 4733    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4734        let mut i = 0;
 4735        let mut regions = self.autoclose_regions.as_slice();
 4736        selections.into_iter().map(move |selection| {
 4737            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4738
 4739            let mut enclosing = None;
 4740            while let Some(pair_state) = regions.get(i) {
 4741                if pair_state.range.end.to_offset(buffer) < range.start {
 4742                    regions = &regions[i + 1..];
 4743                    i = 0;
 4744                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4745                    break;
 4746                } else {
 4747                    if pair_state.selection_id == selection.id {
 4748                        enclosing = Some(pair_state);
 4749                    }
 4750                    i += 1;
 4751                }
 4752            }
 4753
 4754            (selection, enclosing)
 4755        })
 4756    }
 4757
 4758    /// Remove any autoclose regions that no longer contain their selection.
 4759    fn invalidate_autoclose_regions(
 4760        &mut self,
 4761        mut selections: &[Selection<Anchor>],
 4762        buffer: &MultiBufferSnapshot,
 4763    ) {
 4764        self.autoclose_regions.retain(|state| {
 4765            let mut i = 0;
 4766            while let Some(selection) = selections.get(i) {
 4767                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4768                    selections = &selections[1..];
 4769                    continue;
 4770                }
 4771                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4772                    break;
 4773                }
 4774                if selection.id == state.selection_id {
 4775                    return true;
 4776                } else {
 4777                    i += 1;
 4778                }
 4779            }
 4780            false
 4781        });
 4782    }
 4783
 4784    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4785        let offset = position.to_offset(buffer);
 4786        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4787        if offset > word_range.start && kind == Some(CharKind::Word) {
 4788            Some(
 4789                buffer
 4790                    .text_for_range(word_range.start..offset)
 4791                    .collect::<String>(),
 4792            )
 4793        } else {
 4794            None
 4795        }
 4796    }
 4797
 4798    pub fn toggle_inline_values(
 4799        &mut self,
 4800        _: &ToggleInlineValues,
 4801        _: &mut Window,
 4802        cx: &mut Context<Self>,
 4803    ) {
 4804        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4805
 4806        self.refresh_inline_values(cx);
 4807    }
 4808
 4809    pub fn toggle_inlay_hints(
 4810        &mut self,
 4811        _: &ToggleInlayHints,
 4812        _: &mut Window,
 4813        cx: &mut Context<Self>,
 4814    ) {
 4815        self.refresh_inlay_hints(
 4816            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4817            cx,
 4818        );
 4819    }
 4820
 4821    pub fn inlay_hints_enabled(&self) -> bool {
 4822        self.inlay_hint_cache.enabled
 4823    }
 4824
 4825    pub fn inline_values_enabled(&self) -> bool {
 4826        self.inline_value_cache.enabled
 4827    }
 4828
 4829    #[cfg(any(test, feature = "test-support"))]
 4830    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4831        self.display_map
 4832            .read(cx)
 4833            .current_inlays()
 4834            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4835            .cloned()
 4836            .collect()
 4837    }
 4838
 4839    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4840        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4841            return;
 4842        }
 4843
 4844        let reason_description = reason.description();
 4845        let ignore_debounce = matches!(
 4846            reason,
 4847            InlayHintRefreshReason::SettingsChange(_)
 4848                | InlayHintRefreshReason::Toggle(_)
 4849                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4850                | InlayHintRefreshReason::ModifiersChanged(_)
 4851        );
 4852        let (invalidate_cache, required_languages) = match reason {
 4853            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4854                match self.inlay_hint_cache.modifiers_override(enabled) {
 4855                    Some(enabled) => {
 4856                        if enabled {
 4857                            (InvalidationStrategy::RefreshRequested, None)
 4858                        } else {
 4859                            self.splice_inlays(
 4860                                &self
 4861                                    .visible_inlay_hints(cx)
 4862                                    .iter()
 4863                                    .map(|inlay| inlay.id)
 4864                                    .collect::<Vec<InlayId>>(),
 4865                                Vec::new(),
 4866                                cx,
 4867                            );
 4868                            return;
 4869                        }
 4870                    }
 4871                    None => return,
 4872                }
 4873            }
 4874            InlayHintRefreshReason::Toggle(enabled) => {
 4875                if self.inlay_hint_cache.toggle(enabled) {
 4876                    if enabled {
 4877                        (InvalidationStrategy::RefreshRequested, None)
 4878                    } else {
 4879                        self.splice_inlays(
 4880                            &self
 4881                                .visible_inlay_hints(cx)
 4882                                .iter()
 4883                                .map(|inlay| inlay.id)
 4884                                .collect::<Vec<InlayId>>(),
 4885                            Vec::new(),
 4886                            cx,
 4887                        );
 4888                        return;
 4889                    }
 4890                } else {
 4891                    return;
 4892                }
 4893            }
 4894            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4895                match self.inlay_hint_cache.update_settings(
 4896                    &self.buffer,
 4897                    new_settings,
 4898                    self.visible_inlay_hints(cx),
 4899                    cx,
 4900                ) {
 4901                    ControlFlow::Break(Some(InlaySplice {
 4902                        to_remove,
 4903                        to_insert,
 4904                    })) => {
 4905                        self.splice_inlays(&to_remove, to_insert, cx);
 4906                        return;
 4907                    }
 4908                    ControlFlow::Break(None) => return,
 4909                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4910                }
 4911            }
 4912            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4913                if let Some(InlaySplice {
 4914                    to_remove,
 4915                    to_insert,
 4916                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4917                {
 4918                    self.splice_inlays(&to_remove, to_insert, cx);
 4919                }
 4920                self.display_map.update(cx, |display_map, _| {
 4921                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4922                });
 4923                return;
 4924            }
 4925            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4926            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4927                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4928            }
 4929            InlayHintRefreshReason::RefreshRequested => {
 4930                (InvalidationStrategy::RefreshRequested, None)
 4931            }
 4932        };
 4933
 4934        if let Some(InlaySplice {
 4935            to_remove,
 4936            to_insert,
 4937        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4938            reason_description,
 4939            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4940            invalidate_cache,
 4941            ignore_debounce,
 4942            cx,
 4943        ) {
 4944            self.splice_inlays(&to_remove, to_insert, cx);
 4945        }
 4946    }
 4947
 4948    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4949        self.display_map
 4950            .read(cx)
 4951            .current_inlays()
 4952            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4953            .cloned()
 4954            .collect()
 4955    }
 4956
 4957    pub fn excerpts_for_inlay_hints_query(
 4958        &self,
 4959        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4960        cx: &mut Context<Editor>,
 4961    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4962        let Some(project) = self.project.as_ref() else {
 4963            return HashMap::default();
 4964        };
 4965        let project = project.read(cx);
 4966        let multi_buffer = self.buffer().read(cx);
 4967        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4968        let multi_buffer_visible_start = self
 4969            .scroll_manager
 4970            .anchor()
 4971            .anchor
 4972            .to_point(&multi_buffer_snapshot);
 4973        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4974            multi_buffer_visible_start
 4975                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4976            Bias::Left,
 4977        );
 4978        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4979        multi_buffer_snapshot
 4980            .range_to_buffer_ranges(multi_buffer_visible_range)
 4981            .into_iter()
 4982            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4983            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4984                let buffer_file = project::File::from_dyn(buffer.file())?;
 4985                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4986                let worktree_entry = buffer_worktree
 4987                    .read(cx)
 4988                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4989                if worktree_entry.is_ignored {
 4990                    return None;
 4991                }
 4992
 4993                let language = buffer.language()?;
 4994                if let Some(restrict_to_languages) = restrict_to_languages {
 4995                    if !restrict_to_languages.contains(language) {
 4996                        return None;
 4997                    }
 4998                }
 4999                Some((
 5000                    excerpt_id,
 5001                    (
 5002                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5003                        buffer.version().clone(),
 5004                        excerpt_visible_range,
 5005                    ),
 5006                ))
 5007            })
 5008            .collect()
 5009    }
 5010
 5011    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5012        TextLayoutDetails {
 5013            text_system: window.text_system().clone(),
 5014            editor_style: self.style.clone().unwrap(),
 5015            rem_size: window.rem_size(),
 5016            scroll_anchor: self.scroll_manager.anchor(),
 5017            visible_rows: self.visible_line_count(),
 5018            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5019        }
 5020    }
 5021
 5022    pub fn splice_inlays(
 5023        &self,
 5024        to_remove: &[InlayId],
 5025        to_insert: Vec<Inlay>,
 5026        cx: &mut Context<Self>,
 5027    ) {
 5028        self.display_map.update(cx, |display_map, cx| {
 5029            display_map.splice_inlays(to_remove, to_insert, cx)
 5030        });
 5031        cx.notify();
 5032    }
 5033
 5034    fn trigger_on_type_formatting(
 5035        &self,
 5036        input: String,
 5037        window: &mut Window,
 5038        cx: &mut Context<Self>,
 5039    ) -> Option<Task<Result<()>>> {
 5040        if input.len() != 1 {
 5041            return None;
 5042        }
 5043
 5044        let project = self.project.as_ref()?;
 5045        let position = self.selections.newest_anchor().head();
 5046        let (buffer, buffer_position) = self
 5047            .buffer
 5048            .read(cx)
 5049            .text_anchor_for_position(position, cx)?;
 5050
 5051        let settings = language_settings::language_settings(
 5052            buffer
 5053                .read(cx)
 5054                .language_at(buffer_position)
 5055                .map(|l| l.name()),
 5056            buffer.read(cx).file(),
 5057            cx,
 5058        );
 5059        if !settings.use_on_type_format {
 5060            return None;
 5061        }
 5062
 5063        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5064        // hence we do LSP request & edit on host side only — add formats to host's history.
 5065        let push_to_lsp_host_history = true;
 5066        // If this is not the host, append its history with new edits.
 5067        let push_to_client_history = project.read(cx).is_via_collab();
 5068
 5069        let on_type_formatting = project.update(cx, |project, cx| {
 5070            project.on_type_format(
 5071                buffer.clone(),
 5072                buffer_position,
 5073                input,
 5074                push_to_lsp_host_history,
 5075                cx,
 5076            )
 5077        });
 5078        Some(cx.spawn_in(window, async move |editor, cx| {
 5079            if let Some(transaction) = on_type_formatting.await? {
 5080                if push_to_client_history {
 5081                    buffer
 5082                        .update(cx, |buffer, _| {
 5083                            buffer.push_transaction(transaction, Instant::now());
 5084                            buffer.finalize_last_transaction();
 5085                        })
 5086                        .ok();
 5087                }
 5088                editor.update(cx, |editor, cx| {
 5089                    editor.refresh_document_highlights(cx);
 5090                })?;
 5091            }
 5092            Ok(())
 5093        }))
 5094    }
 5095
 5096    pub fn show_word_completions(
 5097        &mut self,
 5098        _: &ShowWordCompletions,
 5099        window: &mut Window,
 5100        cx: &mut Context<Self>,
 5101    ) {
 5102        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5103    }
 5104
 5105    pub fn show_completions(
 5106        &mut self,
 5107        options: &ShowCompletions,
 5108        window: &mut Window,
 5109        cx: &mut Context<Self>,
 5110    ) {
 5111        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5112    }
 5113
 5114    fn open_or_update_completions_menu(
 5115        &mut self,
 5116        requested_source: Option<CompletionsMenuSource>,
 5117        trigger: Option<&str>,
 5118        window: &mut Window,
 5119        cx: &mut Context<Self>,
 5120    ) {
 5121        if self.pending_rename.is_some() {
 5122            return;
 5123        }
 5124
 5125        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5126
 5127        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5128        // inserted and selected. To handle that case, the start of the selection is used so that
 5129        // the menu starts with all choices.
 5130        let position = self
 5131            .selections
 5132            .newest_anchor()
 5133            .start
 5134            .bias_right(&multibuffer_snapshot);
 5135        if position.diff_base_anchor.is_some() {
 5136            return;
 5137        }
 5138        let (buffer, buffer_position) =
 5139            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5140                output
 5141            } else {
 5142                return;
 5143            };
 5144        let buffer_snapshot = buffer.read(cx).snapshot();
 5145
 5146        let query: Option<Arc<String>> =
 5147            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5148
 5149        drop(multibuffer_snapshot);
 5150
 5151        let provider = match requested_source {
 5152            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5153            Some(CompletionsMenuSource::Words) => None,
 5154            Some(CompletionsMenuSource::SnippetChoices) => {
 5155                log::error!("bug: SnippetChoices requested_source is not handled");
 5156                None
 5157            }
 5158        };
 5159
 5160        let sort_completions = provider
 5161            .as_ref()
 5162            .map_or(false, |provider| provider.sort_completions());
 5163
 5164        let filter_completions = provider
 5165            .as_ref()
 5166            .map_or(true, |provider| provider.filter_completions());
 5167
 5168        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5169            if filter_completions {
 5170                menu.filter(query.clone(), provider.clone(), window, cx);
 5171            }
 5172            // When `is_incomplete` is false, no need to re-query completions when the current query
 5173            // is a suffix of the initial query.
 5174            if !menu.is_incomplete {
 5175                // If the new query is a suffix of the old query (typing more characters) and
 5176                // the previous result was complete, the existing completions can be filtered.
 5177                //
 5178                // Note that this is always true for snippet completions.
 5179                let query_matches = match (&menu.initial_query, &query) {
 5180                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5181                    (None, _) => true,
 5182                    _ => false,
 5183                };
 5184                if query_matches {
 5185                    let position_matches = if menu.initial_position == position {
 5186                        true
 5187                    } else {
 5188                        let snapshot = self.buffer.read(cx).read(cx);
 5189                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5190                    };
 5191                    if position_matches {
 5192                        return;
 5193                    }
 5194                }
 5195            }
 5196        };
 5197
 5198        let trigger_kind = match trigger {
 5199            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5200                CompletionTriggerKind::TRIGGER_CHARACTER
 5201            }
 5202            _ => CompletionTriggerKind::INVOKED,
 5203        };
 5204        let completion_context = CompletionContext {
 5205            trigger_character: trigger.and_then(|trigger| {
 5206                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5207                    Some(String::from(trigger))
 5208                } else {
 5209                    None
 5210                }
 5211            }),
 5212            trigger_kind,
 5213        };
 5214
 5215        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5216            buffer_snapshot.surrounding_word(buffer_position)
 5217        {
 5218            let word_to_exclude = buffer_snapshot
 5219                .text_for_range(word_range.clone())
 5220                .collect::<String>();
 5221            (
 5222                buffer_snapshot.anchor_before(word_range.start)
 5223                    ..buffer_snapshot.anchor_after(buffer_position),
 5224                Some(word_to_exclude),
 5225            )
 5226        } else {
 5227            (buffer_position..buffer_position, None)
 5228        };
 5229
 5230        let language = buffer_snapshot
 5231            .language_at(buffer_position)
 5232            .map(|language| language.name());
 5233
 5234        let completion_settings =
 5235            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5236
 5237        let show_completion_documentation = buffer_snapshot
 5238            .settings_at(buffer_position, cx)
 5239            .show_completion_documentation;
 5240
 5241        // The document can be large, so stay in reasonable bounds when searching for words,
 5242        // otherwise completion pop-up might be slow to appear.
 5243        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5244        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5245        let min_word_search = buffer_snapshot.clip_point(
 5246            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5247            Bias::Left,
 5248        );
 5249        let max_word_search = buffer_snapshot.clip_point(
 5250            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5251            Bias::Right,
 5252        );
 5253        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5254            ..buffer_snapshot.point_to_offset(max_word_search);
 5255
 5256        let skip_digits = query
 5257            .as_ref()
 5258            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5259
 5260        let (mut words, provider_responses) = match &provider {
 5261            Some(provider) => {
 5262                let provider_responses = provider.completions(
 5263                    position.excerpt_id,
 5264                    &buffer,
 5265                    buffer_position,
 5266                    completion_context,
 5267                    window,
 5268                    cx,
 5269                );
 5270
 5271                let words = match completion_settings.words {
 5272                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5273                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5274                        .background_spawn(async move {
 5275                            buffer_snapshot.words_in_range(WordsQuery {
 5276                                fuzzy_contents: None,
 5277                                range: word_search_range,
 5278                                skip_digits,
 5279                            })
 5280                        }),
 5281                };
 5282
 5283                (words, provider_responses)
 5284            }
 5285            None => (
 5286                cx.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                Task::ready(Ok(Vec::new())),
 5294            ),
 5295        };
 5296
 5297        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5298
 5299        let id = post_inc(&mut self.next_completion_id);
 5300        let task = cx.spawn_in(window, async move |editor, cx| {
 5301            let Ok(()) = editor.update(cx, |this, _| {
 5302                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5303            }) else {
 5304                return;
 5305            };
 5306
 5307            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5308            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5309            let mut completions = Vec::new();
 5310            let mut is_incomplete = false;
 5311            if let Some(provider_responses) = provider_responses.await.log_err() {
 5312                if !provider_responses.is_empty() {
 5313                    for response in provider_responses {
 5314                        completions.extend(response.completions);
 5315                        is_incomplete = is_incomplete || response.is_incomplete;
 5316                    }
 5317                    if completion_settings.words == WordsCompletionMode::Fallback {
 5318                        words = Task::ready(BTreeMap::default());
 5319                    }
 5320                }
 5321            }
 5322
 5323            let mut words = words.await;
 5324            if let Some(word_to_exclude) = &word_to_exclude {
 5325                words.remove(word_to_exclude);
 5326            }
 5327            for lsp_completion in &completions {
 5328                words.remove(&lsp_completion.new_text);
 5329            }
 5330            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5331                replace_range: word_replace_range.clone(),
 5332                new_text: word.clone(),
 5333                label: CodeLabel::plain(word, None),
 5334                icon_path: None,
 5335                documentation: None,
 5336                source: CompletionSource::BufferWord {
 5337                    word_range,
 5338                    resolved: false,
 5339                },
 5340                insert_text_mode: Some(InsertTextMode::AS_IS),
 5341                confirm: None,
 5342            }));
 5343
 5344            let menu = if completions.is_empty() {
 5345                None
 5346            } else {
 5347                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5348                    let languages = editor
 5349                        .workspace
 5350                        .as_ref()
 5351                        .and_then(|(workspace, _)| workspace.upgrade())
 5352                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5353                    let menu = CompletionsMenu::new(
 5354                        id,
 5355                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5356                        sort_completions,
 5357                        show_completion_documentation,
 5358                        position,
 5359                        query.clone(),
 5360                        is_incomplete,
 5361                        buffer.clone(),
 5362                        completions.into(),
 5363                        snippet_sort_order,
 5364                        languages,
 5365                        language,
 5366                        cx,
 5367                    );
 5368
 5369                    let query = if filter_completions { query } else { None };
 5370                    let matches_task = if let Some(query) = query {
 5371                        menu.do_async_filtering(query, cx)
 5372                    } else {
 5373                        Task::ready(menu.unfiltered_matches())
 5374                    };
 5375                    (menu, matches_task)
 5376                }) else {
 5377                    return;
 5378                };
 5379
 5380                let matches = matches_task.await;
 5381
 5382                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5383                    // Newer menu already set, so exit.
 5384                    match editor.context_menu.borrow().as_ref() {
 5385                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5386                            if prev_menu.id > id {
 5387                                return;
 5388                            }
 5389                        }
 5390                        _ => {}
 5391                    };
 5392
 5393                    // Only valid to take prev_menu because it the new menu is immediately set
 5394                    // below, or the menu is hidden.
 5395                    match editor.context_menu.borrow_mut().take() {
 5396                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5397                            let position_matches =
 5398                                if prev_menu.initial_position == menu.initial_position {
 5399                                    true
 5400                                } else {
 5401                                    let snapshot = editor.buffer.read(cx).read(cx);
 5402                                    prev_menu.initial_position.to_offset(&snapshot)
 5403                                        == menu.initial_position.to_offset(&snapshot)
 5404                                };
 5405                            if position_matches {
 5406                                // Preserve markdown cache before `set_filter_results` because it will
 5407                                // try to populate the documentation cache.
 5408                                menu.preserve_markdown_cache(prev_menu);
 5409                            }
 5410                        }
 5411                        _ => {}
 5412                    };
 5413
 5414                    menu.set_filter_results(matches, provider, window, cx);
 5415                }) else {
 5416                    return;
 5417                };
 5418
 5419                menu.visible().then_some(menu)
 5420            };
 5421
 5422            editor
 5423                .update_in(cx, |editor, window, cx| {
 5424                    if editor.focus_handle.is_focused(window) {
 5425                        if let Some(menu) = menu {
 5426                            *editor.context_menu.borrow_mut() =
 5427                                Some(CodeContextMenu::Completions(menu));
 5428
 5429                            crate::hover_popover::hide_hover(editor, cx);
 5430                            if editor.show_edit_predictions_in_menu() {
 5431                                editor.update_visible_inline_completion(window, cx);
 5432                            } else {
 5433                                editor.discard_inline_completion(false, cx);
 5434                            }
 5435
 5436                            cx.notify();
 5437                            return;
 5438                        }
 5439                    }
 5440
 5441                    if editor.completion_tasks.len() <= 1 {
 5442                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5443                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5444                        // If it was already hidden and we don't show inline completions in the menu, we should
 5445                        // also show the inline-completion when available.
 5446                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5447                            editor.update_visible_inline_completion(window, cx);
 5448                        }
 5449                    }
 5450                })
 5451                .ok();
 5452        });
 5453
 5454        self.completion_tasks.push((id, task));
 5455    }
 5456
 5457    #[cfg(feature = "test-support")]
 5458    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5459        let menu = self.context_menu.borrow();
 5460        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5461            let completions = menu.completions.borrow();
 5462            Some(completions.to_vec())
 5463        } else {
 5464            None
 5465        }
 5466    }
 5467
 5468    pub fn with_completions_menu_matching_id<R>(
 5469        &self,
 5470        id: CompletionId,
 5471        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5472    ) -> R {
 5473        let mut context_menu = self.context_menu.borrow_mut();
 5474        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5475            return f(None);
 5476        };
 5477        if completions_menu.id != id {
 5478            return f(None);
 5479        }
 5480        f(Some(completions_menu))
 5481    }
 5482
 5483    pub fn confirm_completion(
 5484        &mut self,
 5485        action: &ConfirmCompletion,
 5486        window: &mut Window,
 5487        cx: &mut Context<Self>,
 5488    ) -> Option<Task<Result<()>>> {
 5489        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5490        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5491    }
 5492
 5493    pub fn confirm_completion_insert(
 5494        &mut self,
 5495        _: &ConfirmCompletionInsert,
 5496        window: &mut Window,
 5497        cx: &mut Context<Self>,
 5498    ) -> Option<Task<Result<()>>> {
 5499        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5500        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5501    }
 5502
 5503    pub fn confirm_completion_replace(
 5504        &mut self,
 5505        _: &ConfirmCompletionReplace,
 5506        window: &mut Window,
 5507        cx: &mut Context<Self>,
 5508    ) -> Option<Task<Result<()>>> {
 5509        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5510        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5511    }
 5512
 5513    pub fn compose_completion(
 5514        &mut self,
 5515        action: &ComposeCompletion,
 5516        window: &mut Window,
 5517        cx: &mut Context<Self>,
 5518    ) -> Option<Task<Result<()>>> {
 5519        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5520        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5521    }
 5522
 5523    fn do_completion(
 5524        &mut self,
 5525        item_ix: Option<usize>,
 5526        intent: CompletionIntent,
 5527        window: &mut Window,
 5528        cx: &mut Context<Editor>,
 5529    ) -> Option<Task<Result<()>>> {
 5530        use language::ToOffset as _;
 5531
 5532        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5533        else {
 5534            return None;
 5535        };
 5536
 5537        let candidate_id = {
 5538            let entries = completions_menu.entries.borrow();
 5539            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5540            if self.show_edit_predictions_in_menu() {
 5541                self.discard_inline_completion(true, cx);
 5542            }
 5543            mat.candidate_id
 5544        };
 5545
 5546        let completion = completions_menu
 5547            .completions
 5548            .borrow()
 5549            .get(candidate_id)?
 5550            .clone();
 5551        cx.stop_propagation();
 5552
 5553        let buffer_handle = completions_menu.buffer.clone();
 5554
 5555        let CompletionEdit {
 5556            new_text,
 5557            snippet,
 5558            replace_range,
 5559        } = process_completion_for_edit(
 5560            &completion,
 5561            intent,
 5562            &buffer_handle,
 5563            &completions_menu.initial_position.text_anchor,
 5564            cx,
 5565        );
 5566
 5567        let buffer = buffer_handle.read(cx);
 5568        let snapshot = self.buffer.read(cx).snapshot(cx);
 5569        let newest_anchor = self.selections.newest_anchor();
 5570        let replace_range_multibuffer = {
 5571            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5572            let multibuffer_anchor = snapshot
 5573                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5574                .unwrap()
 5575                ..snapshot
 5576                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5577                    .unwrap();
 5578            multibuffer_anchor.start.to_offset(&snapshot)
 5579                ..multibuffer_anchor.end.to_offset(&snapshot)
 5580        };
 5581        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5582            return None;
 5583        }
 5584
 5585        let old_text = buffer
 5586            .text_for_range(replace_range.clone())
 5587            .collect::<String>();
 5588        let lookbehind = newest_anchor
 5589            .start
 5590            .text_anchor
 5591            .to_offset(buffer)
 5592            .saturating_sub(replace_range.start);
 5593        let lookahead = replace_range
 5594            .end
 5595            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5596        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5597        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5598
 5599        let selections = self.selections.all::<usize>(cx);
 5600        let mut ranges = Vec::new();
 5601        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5602
 5603        for selection in &selections {
 5604            let range = if selection.id == newest_anchor.id {
 5605                replace_range_multibuffer.clone()
 5606            } else {
 5607                let mut range = selection.range();
 5608
 5609                // if prefix is present, don't duplicate it
 5610                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5611                    range.start = range.start.saturating_sub(lookbehind);
 5612
 5613                    // if suffix is also present, mimic the newest cursor and replace it
 5614                    if selection.id != newest_anchor.id
 5615                        && snapshot.contains_str_at(range.end, suffix)
 5616                    {
 5617                        range.end += lookahead;
 5618                    }
 5619                }
 5620                range
 5621            };
 5622
 5623            ranges.push(range.clone());
 5624
 5625            if !self.linked_edit_ranges.is_empty() {
 5626                let start_anchor = snapshot.anchor_before(range.start);
 5627                let end_anchor = snapshot.anchor_after(range.end);
 5628                if let Some(ranges) = self
 5629                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5630                {
 5631                    for (buffer, edits) in ranges {
 5632                        linked_edits
 5633                            .entry(buffer.clone())
 5634                            .or_default()
 5635                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5636                    }
 5637                }
 5638            }
 5639        }
 5640
 5641        let common_prefix_len = old_text
 5642            .chars()
 5643            .zip(new_text.chars())
 5644            .take_while(|(a, b)| a == b)
 5645            .map(|(a, _)| a.len_utf8())
 5646            .sum::<usize>();
 5647
 5648        cx.emit(EditorEvent::InputHandled {
 5649            utf16_range_to_replace: None,
 5650            text: new_text[common_prefix_len..].into(),
 5651        });
 5652
 5653        self.transact(window, cx, |this, window, cx| {
 5654            if let Some(mut snippet) = snippet {
 5655                snippet.text = new_text.to_string();
 5656                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5657            } else {
 5658                this.buffer.update(cx, |buffer, cx| {
 5659                    let auto_indent = match completion.insert_text_mode {
 5660                        Some(InsertTextMode::AS_IS) => None,
 5661                        _ => this.autoindent_mode.clone(),
 5662                    };
 5663                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5664                    buffer.edit(edits, auto_indent, cx);
 5665                });
 5666            }
 5667            for (buffer, edits) in linked_edits {
 5668                buffer.update(cx, |buffer, cx| {
 5669                    let snapshot = buffer.snapshot();
 5670                    let edits = edits
 5671                        .into_iter()
 5672                        .map(|(range, text)| {
 5673                            use text::ToPoint as TP;
 5674                            let end_point = TP::to_point(&range.end, &snapshot);
 5675                            let start_point = TP::to_point(&range.start, &snapshot);
 5676                            (start_point..end_point, text)
 5677                        })
 5678                        .sorted_by_key(|(range, _)| range.start);
 5679                    buffer.edit(edits, None, cx);
 5680                })
 5681            }
 5682
 5683            this.refresh_inline_completion(true, false, window, cx);
 5684        });
 5685
 5686        let show_new_completions_on_confirm = completion
 5687            .confirm
 5688            .as_ref()
 5689            .map_or(false, |confirm| confirm(intent, window, cx));
 5690        if show_new_completions_on_confirm {
 5691            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5692        }
 5693
 5694        let provider = self.completion_provider.as_ref()?;
 5695        drop(completion);
 5696        let apply_edits = provider.apply_additional_edits_for_completion(
 5697            buffer_handle,
 5698            completions_menu.completions.clone(),
 5699            candidate_id,
 5700            true,
 5701            cx,
 5702        );
 5703
 5704        let editor_settings = EditorSettings::get_global(cx);
 5705        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5706            // After the code completion is finished, users often want to know what signatures are needed.
 5707            // so we should automatically call signature_help
 5708            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5709        }
 5710
 5711        Some(cx.foreground_executor().spawn(async move {
 5712            apply_edits.await?;
 5713            Ok(())
 5714        }))
 5715    }
 5716
 5717    pub fn toggle_code_actions(
 5718        &mut self,
 5719        action: &ToggleCodeActions,
 5720        window: &mut Window,
 5721        cx: &mut Context<Self>,
 5722    ) {
 5723        let quick_launch = action.quick_launch;
 5724        let mut context_menu = self.context_menu.borrow_mut();
 5725        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5726            if code_actions.deployed_from == action.deployed_from {
 5727                // Toggle if we're selecting the same one
 5728                *context_menu = None;
 5729                cx.notify();
 5730                return;
 5731            } else {
 5732                // Otherwise, clear it and start a new one
 5733                *context_menu = None;
 5734                cx.notify();
 5735            }
 5736        }
 5737        drop(context_menu);
 5738        let snapshot = self.snapshot(window, cx);
 5739        let deployed_from = action.deployed_from.clone();
 5740        let action = action.clone();
 5741        self.completion_tasks.clear();
 5742        self.discard_inline_completion(false, cx);
 5743
 5744        let multibuffer_point = match &action.deployed_from {
 5745            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5746                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5747            }
 5748            _ => self.selections.newest::<Point>(cx).head(),
 5749        };
 5750        let Some((buffer, buffer_row)) = snapshot
 5751            .buffer_snapshot
 5752            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5753            .and_then(|(buffer_snapshot, range)| {
 5754                self.buffer()
 5755                    .read(cx)
 5756                    .buffer(buffer_snapshot.remote_id())
 5757                    .map(|buffer| (buffer, range.start.row))
 5758            })
 5759        else {
 5760            return;
 5761        };
 5762        let buffer_id = buffer.read(cx).remote_id();
 5763        let tasks = self
 5764            .tasks
 5765            .get(&(buffer_id, buffer_row))
 5766            .map(|t| Arc::new(t.to_owned()));
 5767
 5768        if !self.focus_handle.is_focused(window) {
 5769            return;
 5770        }
 5771        let project = self.project.clone();
 5772
 5773        let code_actions_task = match deployed_from {
 5774            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5775            _ => self.code_actions(buffer_row, window, cx),
 5776        };
 5777
 5778        let runnable_task = match deployed_from {
 5779            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5780            _ => {
 5781                let mut task_context_task = Task::ready(None);
 5782                if let Some(tasks) = &tasks {
 5783                    if let Some(project) = project {
 5784                        task_context_task =
 5785                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5786                    }
 5787                }
 5788
 5789                cx.spawn_in(window, {
 5790                    let buffer = buffer.clone();
 5791                    async move |editor, cx| {
 5792                        let task_context = task_context_task.await;
 5793
 5794                        let resolved_tasks =
 5795                            tasks
 5796                                .zip(task_context.clone())
 5797                                .map(|(tasks, task_context)| ResolvedTasks {
 5798                                    templates: tasks.resolve(&task_context).collect(),
 5799                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5800                                        multibuffer_point.row,
 5801                                        tasks.column,
 5802                                    )),
 5803                                });
 5804                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5805                            editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5806                        })?;
 5807                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5808                    }
 5809                })
 5810            }
 5811        };
 5812
 5813        cx.spawn_in(window, async move |editor, cx| {
 5814            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5815            let code_actions = code_actions_task.await;
 5816            let spawn_straight_away = quick_launch
 5817                && resolved_tasks
 5818                    .as_ref()
 5819                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5820                && code_actions
 5821                    .as_ref()
 5822                    .map_or(true, |actions| actions.is_empty())
 5823                && debug_scenarios.is_empty();
 5824
 5825            editor.update_in(cx, |editor, window, cx| {
 5826                crate::hover_popover::hide_hover(editor, cx);
 5827                *editor.context_menu.borrow_mut() =
 5828                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5829                        buffer,
 5830                        actions: CodeActionContents::new(
 5831                            resolved_tasks,
 5832                            code_actions,
 5833                            debug_scenarios,
 5834                            task_context.unwrap_or_default(),
 5835                        ),
 5836                        selected_item: Default::default(),
 5837                        scroll_handle: UniformListScrollHandle::default(),
 5838                        deployed_from,
 5839                    }));
 5840                if spawn_straight_away {
 5841                    if let Some(task) = editor.confirm_code_action(
 5842                        &ConfirmCodeAction { item_ix: Some(0) },
 5843                        window,
 5844                        cx,
 5845                    ) {
 5846                        cx.notify();
 5847                        return task;
 5848                    }
 5849                }
 5850
 5851                Task::ready(Ok(()))
 5852            })
 5853        })
 5854        .detach_and_log_err(cx);
 5855    }
 5856
 5857    fn debug_scenarios(
 5858        &mut self,
 5859        resolved_tasks: &Option<ResolvedTasks>,
 5860        buffer: &Entity<Buffer>,
 5861        cx: &mut App,
 5862    ) -> Vec<task::DebugScenario> {
 5863        if cx.has_flag::<DebuggerFeatureFlag>() {
 5864            maybe!({
 5865                let project = self.project.as_ref()?;
 5866                let dap_store = project.read(cx).dap_store();
 5867                let mut scenarios = vec![];
 5868                let resolved_tasks = resolved_tasks.as_ref()?;
 5869                let buffer = buffer.read(cx);
 5870                let language = buffer.language()?;
 5871                let file = buffer.file();
 5872                let debug_adapter = language_settings(language.name().into(), file, cx)
 5873                    .debuggers
 5874                    .first()
 5875                    .map(SharedString::from)
 5876                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5877
 5878                dap_store.update(cx, |dap_store, cx| {
 5879                    for (_, task) in &resolved_tasks.templates {
 5880                        if let Some(scenario) = dap_store.debug_scenario_for_build_task(
 5881                            task.original_task().clone(),
 5882                            debug_adapter.clone().into(),
 5883                            task.display_label().to_owned().into(),
 5884                            cx,
 5885                        ) {
 5886                            scenarios.push(scenario);
 5887                        }
 5888                    }
 5889                });
 5890                Some(scenarios)
 5891            })
 5892            .unwrap_or_default()
 5893        } else {
 5894            vec![]
 5895        }
 5896    }
 5897
 5898    fn code_actions(
 5899        &mut self,
 5900        buffer_row: u32,
 5901        window: &mut Window,
 5902        cx: &mut Context<Self>,
 5903    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5904        let mut task = self.code_actions_task.take();
 5905        cx.spawn_in(window, async move |editor, cx| {
 5906            while let Some(prev_task) = task {
 5907                prev_task.await.log_err();
 5908                task = editor
 5909                    .update(cx, |this, _| this.code_actions_task.take())
 5910                    .ok()?;
 5911            }
 5912
 5913            editor
 5914                .update(cx, |editor, cx| {
 5915                    editor
 5916                        .available_code_actions
 5917                        .clone()
 5918                        .and_then(|(location, code_actions)| {
 5919                            let snapshot = location.buffer.read(cx).snapshot();
 5920                            let point_range = location.range.to_point(&snapshot);
 5921                            let point_range = point_range.start.row..=point_range.end.row;
 5922                            if point_range.contains(&buffer_row) {
 5923                                Some(code_actions)
 5924                            } else {
 5925                                None
 5926                            }
 5927                        })
 5928                })
 5929                .ok()
 5930                .flatten()
 5931        })
 5932    }
 5933
 5934    pub fn confirm_code_action(
 5935        &mut self,
 5936        action: &ConfirmCodeAction,
 5937        window: &mut Window,
 5938        cx: &mut Context<Self>,
 5939    ) -> Option<Task<Result<()>>> {
 5940        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5941
 5942        let actions_menu =
 5943            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5944                menu
 5945            } else {
 5946                return None;
 5947            };
 5948
 5949        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5950        let action = actions_menu.actions.get(action_ix)?;
 5951        let title = action.label();
 5952        let buffer = actions_menu.buffer;
 5953        let workspace = self.workspace()?;
 5954
 5955        match action {
 5956            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5957                workspace.update(cx, |workspace, cx| {
 5958                    workspace.schedule_resolved_task(
 5959                        task_source_kind,
 5960                        resolved_task,
 5961                        false,
 5962                        window,
 5963                        cx,
 5964                    );
 5965
 5966                    Some(Task::ready(Ok(())))
 5967                })
 5968            }
 5969            CodeActionsItem::CodeAction {
 5970                excerpt_id,
 5971                action,
 5972                provider,
 5973            } => {
 5974                let apply_code_action =
 5975                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5976                let workspace = workspace.downgrade();
 5977                Some(cx.spawn_in(window, async move |editor, cx| {
 5978                    let project_transaction = apply_code_action.await?;
 5979                    Self::open_project_transaction(
 5980                        &editor,
 5981                        workspace,
 5982                        project_transaction,
 5983                        title,
 5984                        cx,
 5985                    )
 5986                    .await
 5987                }))
 5988            }
 5989            CodeActionsItem::DebugScenario(scenario) => {
 5990                let context = actions_menu.actions.context.clone();
 5991
 5992                workspace.update(cx, |workspace, cx| {
 5993                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5994                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5995                });
 5996                Some(Task::ready(Ok(())))
 5997            }
 5998        }
 5999    }
 6000
 6001    pub async fn open_project_transaction(
 6002        this: &WeakEntity<Editor>,
 6003        workspace: WeakEntity<Workspace>,
 6004        transaction: ProjectTransaction,
 6005        title: String,
 6006        cx: &mut AsyncWindowContext,
 6007    ) -> Result<()> {
 6008        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6009        cx.update(|_, cx| {
 6010            entries.sort_unstable_by_key(|(buffer, _)| {
 6011                buffer.read(cx).file().map(|f| f.path().clone())
 6012            });
 6013        })?;
 6014
 6015        // If the project transaction's edits are all contained within this editor, then
 6016        // avoid opening a new editor to display them.
 6017
 6018        if let Some((buffer, transaction)) = entries.first() {
 6019            if entries.len() == 1 {
 6020                let excerpt = this.update(cx, |editor, cx| {
 6021                    editor
 6022                        .buffer()
 6023                        .read(cx)
 6024                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6025                })?;
 6026                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6027                    if excerpted_buffer == *buffer {
 6028                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6029                            let excerpt_range = excerpt_range.to_offset(buffer);
 6030                            buffer
 6031                                .edited_ranges_for_transaction::<usize>(transaction)
 6032                                .all(|range| {
 6033                                    excerpt_range.start <= range.start
 6034                                        && excerpt_range.end >= range.end
 6035                                })
 6036                        })?;
 6037
 6038                        if all_edits_within_excerpt {
 6039                            return Ok(());
 6040                        }
 6041                    }
 6042                }
 6043            }
 6044        } else {
 6045            return Ok(());
 6046        }
 6047
 6048        let mut ranges_to_highlight = Vec::new();
 6049        let excerpt_buffer = cx.new(|cx| {
 6050            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6051            for (buffer_handle, transaction) in &entries {
 6052                let edited_ranges = buffer_handle
 6053                    .read(cx)
 6054                    .edited_ranges_for_transaction::<Point>(transaction)
 6055                    .collect::<Vec<_>>();
 6056                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6057                    PathKey::for_buffer(buffer_handle, cx),
 6058                    buffer_handle.clone(),
 6059                    edited_ranges,
 6060                    DEFAULT_MULTIBUFFER_CONTEXT,
 6061                    cx,
 6062                );
 6063
 6064                ranges_to_highlight.extend(ranges);
 6065            }
 6066            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6067            multibuffer
 6068        })?;
 6069
 6070        workspace.update_in(cx, |workspace, window, cx| {
 6071            let project = workspace.project().clone();
 6072            let editor =
 6073                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6074            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6075            editor.update(cx, |editor, cx| {
 6076                editor.highlight_background::<Self>(
 6077                    &ranges_to_highlight,
 6078                    |theme| theme.editor_highlighted_line_background,
 6079                    cx,
 6080                );
 6081            });
 6082        })?;
 6083
 6084        Ok(())
 6085    }
 6086
 6087    pub fn clear_code_action_providers(&mut self) {
 6088        self.code_action_providers.clear();
 6089        self.available_code_actions.take();
 6090    }
 6091
 6092    pub fn add_code_action_provider(
 6093        &mut self,
 6094        provider: Rc<dyn CodeActionProvider>,
 6095        window: &mut Window,
 6096        cx: &mut Context<Self>,
 6097    ) {
 6098        if self
 6099            .code_action_providers
 6100            .iter()
 6101            .any(|existing_provider| existing_provider.id() == provider.id())
 6102        {
 6103            return;
 6104        }
 6105
 6106        self.code_action_providers.push(provider);
 6107        self.refresh_code_actions(window, cx);
 6108    }
 6109
 6110    pub fn remove_code_action_provider(
 6111        &mut self,
 6112        id: Arc<str>,
 6113        window: &mut Window,
 6114        cx: &mut Context<Self>,
 6115    ) {
 6116        self.code_action_providers
 6117            .retain(|provider| provider.id() != id);
 6118        self.refresh_code_actions(window, cx);
 6119    }
 6120
 6121    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6122        !self.code_action_providers.is_empty()
 6123            && EditorSettings::get_global(cx).toolbar.code_actions
 6124    }
 6125
 6126    pub fn has_available_code_actions(&self) -> bool {
 6127        self.available_code_actions
 6128            .as_ref()
 6129            .is_some_and(|(_, actions)| !actions.is_empty())
 6130    }
 6131
 6132    fn render_inline_code_actions(
 6133        &self,
 6134        icon_size: ui::IconSize,
 6135        display_row: DisplayRow,
 6136        is_active: bool,
 6137        cx: &mut Context<Self>,
 6138    ) -> AnyElement {
 6139        let show_tooltip = !self.context_menu_visible();
 6140        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6141            .icon_size(icon_size)
 6142            .shape(ui::IconButtonShape::Square)
 6143            .style(ButtonStyle::Transparent)
 6144            .icon_color(ui::Color::Hidden)
 6145            .toggle_state(is_active)
 6146            .when(show_tooltip, |this| {
 6147                this.tooltip({
 6148                    let focus_handle = self.focus_handle.clone();
 6149                    move |window, cx| {
 6150                        Tooltip::for_action_in(
 6151                            "Toggle Code Actions",
 6152                            &ToggleCodeActions {
 6153                                deployed_from: None,
 6154                                quick_launch: false,
 6155                            },
 6156                            &focus_handle,
 6157                            window,
 6158                            cx,
 6159                        )
 6160                    }
 6161                })
 6162            })
 6163            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6164                window.focus(&editor.focus_handle(cx));
 6165                editor.toggle_code_actions(
 6166                    &crate::actions::ToggleCodeActions {
 6167                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6168                            display_row,
 6169                        )),
 6170                        quick_launch: false,
 6171                    },
 6172                    window,
 6173                    cx,
 6174                );
 6175            }))
 6176            .into_any_element()
 6177    }
 6178
 6179    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6180        &self.context_menu
 6181    }
 6182
 6183    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6184        let newest_selection = self.selections.newest_anchor().clone();
 6185        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6186        let buffer = self.buffer.read(cx);
 6187        if newest_selection.head().diff_base_anchor.is_some() {
 6188            return None;
 6189        }
 6190        let (start_buffer, start) =
 6191            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6192        let (end_buffer, end) =
 6193            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6194        if start_buffer != end_buffer {
 6195            return None;
 6196        }
 6197
 6198        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6199            cx.background_executor()
 6200                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6201                .await;
 6202
 6203            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6204                let providers = this.code_action_providers.clone();
 6205                let tasks = this
 6206                    .code_action_providers
 6207                    .iter()
 6208                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6209                    .collect::<Vec<_>>();
 6210                (providers, tasks)
 6211            })?;
 6212
 6213            let mut actions = Vec::new();
 6214            for (provider, provider_actions) in
 6215                providers.into_iter().zip(future::join_all(tasks).await)
 6216            {
 6217                if let Some(provider_actions) = provider_actions.log_err() {
 6218                    actions.extend(provider_actions.into_iter().map(|action| {
 6219                        AvailableCodeAction {
 6220                            excerpt_id: newest_selection.start.excerpt_id,
 6221                            action,
 6222                            provider: provider.clone(),
 6223                        }
 6224                    }));
 6225                }
 6226            }
 6227
 6228            this.update(cx, |this, cx| {
 6229                this.available_code_actions = if actions.is_empty() {
 6230                    None
 6231                } else {
 6232                    Some((
 6233                        Location {
 6234                            buffer: start_buffer,
 6235                            range: start..end,
 6236                        },
 6237                        actions.into(),
 6238                    ))
 6239                };
 6240                cx.notify();
 6241            })
 6242        }));
 6243        None
 6244    }
 6245
 6246    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6247        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6248            self.show_git_blame_inline = false;
 6249
 6250            self.show_git_blame_inline_delay_task =
 6251                Some(cx.spawn_in(window, async move |this, cx| {
 6252                    cx.background_executor().timer(delay).await;
 6253
 6254                    this.update(cx, |this, cx| {
 6255                        this.show_git_blame_inline = true;
 6256                        cx.notify();
 6257                    })
 6258                    .log_err();
 6259                }));
 6260        }
 6261    }
 6262
 6263    fn show_blame_popover(
 6264        &mut self,
 6265        blame_entry: &BlameEntry,
 6266        position: gpui::Point<Pixels>,
 6267        cx: &mut Context<Self>,
 6268    ) {
 6269        if let Some(state) = &mut self.inline_blame_popover {
 6270            state.hide_task.take();
 6271            cx.notify();
 6272        } else {
 6273            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6274            let show_task = cx.spawn(async move |editor, cx| {
 6275                cx.background_executor()
 6276                    .timer(std::time::Duration::from_millis(delay))
 6277                    .await;
 6278                editor
 6279                    .update(cx, |editor, cx| {
 6280                        if let Some(state) = &mut editor.inline_blame_popover {
 6281                            state.show_task = None;
 6282                            cx.notify();
 6283                        }
 6284                    })
 6285                    .ok();
 6286            });
 6287            let Some(blame) = self.blame.as_ref() else {
 6288                return;
 6289            };
 6290            let blame = blame.read(cx);
 6291            let details = blame.details_for_entry(&blame_entry);
 6292            let markdown = cx.new(|cx| {
 6293                Markdown::new(
 6294                    details
 6295                        .as_ref()
 6296                        .map(|message| message.message.clone())
 6297                        .unwrap_or_default(),
 6298                    None,
 6299                    None,
 6300                    cx,
 6301                )
 6302            });
 6303            self.inline_blame_popover = Some(InlineBlamePopover {
 6304                position,
 6305                show_task: Some(show_task),
 6306                hide_task: None,
 6307                popover_bounds: None,
 6308                popover_state: InlineBlamePopoverState {
 6309                    scroll_handle: ScrollHandle::new(),
 6310                    commit_message: details,
 6311                    markdown,
 6312                },
 6313            });
 6314        }
 6315    }
 6316
 6317    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6318        if let Some(state) = &mut self.inline_blame_popover {
 6319            if state.show_task.is_some() {
 6320                self.inline_blame_popover.take();
 6321                cx.notify();
 6322            } else {
 6323                let hide_task = cx.spawn(async move |editor, cx| {
 6324                    cx.background_executor()
 6325                        .timer(std::time::Duration::from_millis(100))
 6326                        .await;
 6327                    editor
 6328                        .update(cx, |editor, cx| {
 6329                            editor.inline_blame_popover.take();
 6330                            cx.notify();
 6331                        })
 6332                        .ok();
 6333                });
 6334                state.hide_task = Some(hide_task);
 6335            }
 6336        }
 6337    }
 6338
 6339    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6340        if self.pending_rename.is_some() {
 6341            return None;
 6342        }
 6343
 6344        let provider = self.semantics_provider.clone()?;
 6345        let buffer = self.buffer.read(cx);
 6346        let newest_selection = self.selections.newest_anchor().clone();
 6347        let cursor_position = newest_selection.head();
 6348        let (cursor_buffer, cursor_buffer_position) =
 6349            buffer.text_anchor_for_position(cursor_position, cx)?;
 6350        let (tail_buffer, tail_buffer_position) =
 6351            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6352        if cursor_buffer != tail_buffer {
 6353            return None;
 6354        }
 6355
 6356        let snapshot = cursor_buffer.read(cx).snapshot();
 6357        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6358        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6359        if start_word_range != end_word_range {
 6360            self.document_highlights_task.take();
 6361            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6362            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6363            return None;
 6364        }
 6365
 6366        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6367        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6368            cx.background_executor()
 6369                .timer(Duration::from_millis(debounce))
 6370                .await;
 6371
 6372            let highlights = if let Some(highlights) = cx
 6373                .update(|cx| {
 6374                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6375                })
 6376                .ok()
 6377                .flatten()
 6378            {
 6379                highlights.await.log_err()
 6380            } else {
 6381                None
 6382            };
 6383
 6384            if let Some(highlights) = highlights {
 6385                this.update(cx, |this, cx| {
 6386                    if this.pending_rename.is_some() {
 6387                        return;
 6388                    }
 6389
 6390                    let buffer_id = cursor_position.buffer_id;
 6391                    let buffer = this.buffer.read(cx);
 6392                    if !buffer
 6393                        .text_anchor_for_position(cursor_position, cx)
 6394                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6395                    {
 6396                        return;
 6397                    }
 6398
 6399                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6400                    let mut write_ranges = Vec::new();
 6401                    let mut read_ranges = Vec::new();
 6402                    for highlight in highlights {
 6403                        for (excerpt_id, excerpt_range) in
 6404                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6405                        {
 6406                            let start = highlight
 6407                                .range
 6408                                .start
 6409                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6410                            let end = highlight
 6411                                .range
 6412                                .end
 6413                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6414                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6415                                continue;
 6416                            }
 6417
 6418                            let range = Anchor {
 6419                                buffer_id,
 6420                                excerpt_id,
 6421                                text_anchor: start,
 6422                                diff_base_anchor: None,
 6423                            }..Anchor {
 6424                                buffer_id,
 6425                                excerpt_id,
 6426                                text_anchor: end,
 6427                                diff_base_anchor: None,
 6428                            };
 6429                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6430                                write_ranges.push(range);
 6431                            } else {
 6432                                read_ranges.push(range);
 6433                            }
 6434                        }
 6435                    }
 6436
 6437                    this.highlight_background::<DocumentHighlightRead>(
 6438                        &read_ranges,
 6439                        |theme| theme.editor_document_highlight_read_background,
 6440                        cx,
 6441                    );
 6442                    this.highlight_background::<DocumentHighlightWrite>(
 6443                        &write_ranges,
 6444                        |theme| theme.editor_document_highlight_write_background,
 6445                        cx,
 6446                    );
 6447                    cx.notify();
 6448                })
 6449                .log_err();
 6450            }
 6451        }));
 6452        None
 6453    }
 6454
 6455    fn prepare_highlight_query_from_selection(
 6456        &mut self,
 6457        cx: &mut Context<Editor>,
 6458    ) -> Option<(String, Range<Anchor>)> {
 6459        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6460            return None;
 6461        }
 6462        if !EditorSettings::get_global(cx).selection_highlight {
 6463            return None;
 6464        }
 6465        if self.selections.count() != 1 || self.selections.line_mode {
 6466            return None;
 6467        }
 6468        let selection = self.selections.newest::<Point>(cx);
 6469        if selection.is_empty() || selection.start.row != selection.end.row {
 6470            return None;
 6471        }
 6472        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6473        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6474        let query = multi_buffer_snapshot
 6475            .text_for_range(selection_anchor_range.clone())
 6476            .collect::<String>();
 6477        if query.trim().is_empty() {
 6478            return None;
 6479        }
 6480        Some((query, selection_anchor_range))
 6481    }
 6482
 6483    fn update_selection_occurrence_highlights(
 6484        &mut self,
 6485        query_text: String,
 6486        query_range: Range<Anchor>,
 6487        multi_buffer_range_to_query: Range<Point>,
 6488        use_debounce: bool,
 6489        window: &mut Window,
 6490        cx: &mut Context<Editor>,
 6491    ) -> Task<()> {
 6492        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6493        cx.spawn_in(window, async move |editor, cx| {
 6494            if use_debounce {
 6495                cx.background_executor()
 6496                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6497                    .await;
 6498            }
 6499            let match_task = cx.background_spawn(async move {
 6500                let buffer_ranges = multi_buffer_snapshot
 6501                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6502                    .into_iter()
 6503                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6504                let mut match_ranges = Vec::new();
 6505                let Ok(regex) = project::search::SearchQuery::text(
 6506                    query_text.clone(),
 6507                    false,
 6508                    false,
 6509                    false,
 6510                    Default::default(),
 6511                    Default::default(),
 6512                    false,
 6513                    None,
 6514                ) else {
 6515                    return Vec::default();
 6516                };
 6517                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6518                    match_ranges.extend(
 6519                        regex
 6520                            .search(&buffer_snapshot, Some(search_range.clone()))
 6521                            .await
 6522                            .into_iter()
 6523                            .filter_map(|match_range| {
 6524                                let match_start = buffer_snapshot
 6525                                    .anchor_after(search_range.start + match_range.start);
 6526                                let match_end = buffer_snapshot
 6527                                    .anchor_before(search_range.start + match_range.end);
 6528                                let match_anchor_range = Anchor::range_in_buffer(
 6529                                    excerpt_id,
 6530                                    buffer_snapshot.remote_id(),
 6531                                    match_start..match_end,
 6532                                );
 6533                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6534                            }),
 6535                    );
 6536                }
 6537                match_ranges
 6538            });
 6539            let match_ranges = match_task.await;
 6540            editor
 6541                .update_in(cx, |editor, _, cx| {
 6542                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6543                    if !match_ranges.is_empty() {
 6544                        editor.highlight_background::<SelectedTextHighlight>(
 6545                            &match_ranges,
 6546                            |theme| theme.editor_document_highlight_bracket_background,
 6547                            cx,
 6548                        )
 6549                    }
 6550                })
 6551                .log_err();
 6552        })
 6553    }
 6554
 6555    fn refresh_selected_text_highlights(
 6556        &mut self,
 6557        on_buffer_edit: bool,
 6558        window: &mut Window,
 6559        cx: &mut Context<Editor>,
 6560    ) {
 6561        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6562        else {
 6563            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6564            self.quick_selection_highlight_task.take();
 6565            self.debounced_selection_highlight_task.take();
 6566            return;
 6567        };
 6568        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6569        if on_buffer_edit
 6570            || self
 6571                .quick_selection_highlight_task
 6572                .as_ref()
 6573                .map_or(true, |(prev_anchor_range, _)| {
 6574                    prev_anchor_range != &query_range
 6575                })
 6576        {
 6577            let multi_buffer_visible_start = self
 6578                .scroll_manager
 6579                .anchor()
 6580                .anchor
 6581                .to_point(&multi_buffer_snapshot);
 6582            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6583                multi_buffer_visible_start
 6584                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6585                Bias::Left,
 6586            );
 6587            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6588            self.quick_selection_highlight_task = Some((
 6589                query_range.clone(),
 6590                self.update_selection_occurrence_highlights(
 6591                    query_text.clone(),
 6592                    query_range.clone(),
 6593                    multi_buffer_visible_range,
 6594                    false,
 6595                    window,
 6596                    cx,
 6597                ),
 6598            ));
 6599        }
 6600        if on_buffer_edit
 6601            || self
 6602                .debounced_selection_highlight_task
 6603                .as_ref()
 6604                .map_or(true, |(prev_anchor_range, _)| {
 6605                    prev_anchor_range != &query_range
 6606                })
 6607        {
 6608            let multi_buffer_start = multi_buffer_snapshot
 6609                .anchor_before(0)
 6610                .to_point(&multi_buffer_snapshot);
 6611            let multi_buffer_end = multi_buffer_snapshot
 6612                .anchor_after(multi_buffer_snapshot.len())
 6613                .to_point(&multi_buffer_snapshot);
 6614            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6615            self.debounced_selection_highlight_task = Some((
 6616                query_range.clone(),
 6617                self.update_selection_occurrence_highlights(
 6618                    query_text,
 6619                    query_range,
 6620                    multi_buffer_full_range,
 6621                    true,
 6622                    window,
 6623                    cx,
 6624                ),
 6625            ));
 6626        }
 6627    }
 6628
 6629    pub fn refresh_inline_completion(
 6630        &mut self,
 6631        debounce: bool,
 6632        user_requested: bool,
 6633        window: &mut Window,
 6634        cx: &mut Context<Self>,
 6635    ) -> Option<()> {
 6636        let provider = self.edit_prediction_provider()?;
 6637        let cursor = self.selections.newest_anchor().head();
 6638        let (buffer, cursor_buffer_position) =
 6639            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6640
 6641        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6642            self.discard_inline_completion(false, cx);
 6643            return None;
 6644        }
 6645
 6646        if !user_requested
 6647            && (!self.should_show_edit_predictions()
 6648                || !self.is_focused(window)
 6649                || buffer.read(cx).is_empty())
 6650        {
 6651            self.discard_inline_completion(false, cx);
 6652            return None;
 6653        }
 6654
 6655        self.update_visible_inline_completion(window, cx);
 6656        provider.refresh(
 6657            self.project.clone(),
 6658            buffer,
 6659            cursor_buffer_position,
 6660            debounce,
 6661            cx,
 6662        );
 6663        Some(())
 6664    }
 6665
 6666    fn show_edit_predictions_in_menu(&self) -> bool {
 6667        match self.edit_prediction_settings {
 6668            EditPredictionSettings::Disabled => false,
 6669            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6670        }
 6671    }
 6672
 6673    pub fn edit_predictions_enabled(&self) -> bool {
 6674        match self.edit_prediction_settings {
 6675            EditPredictionSettings::Disabled => false,
 6676            EditPredictionSettings::Enabled { .. } => true,
 6677        }
 6678    }
 6679
 6680    fn edit_prediction_requires_modifier(&self) -> bool {
 6681        match self.edit_prediction_settings {
 6682            EditPredictionSettings::Disabled => false,
 6683            EditPredictionSettings::Enabled {
 6684                preview_requires_modifier,
 6685                ..
 6686            } => preview_requires_modifier,
 6687        }
 6688    }
 6689
 6690    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6691        if self.edit_prediction_provider.is_none() {
 6692            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6693        } else {
 6694            let selection = self.selections.newest_anchor();
 6695            let cursor = selection.head();
 6696
 6697            if let Some((buffer, cursor_buffer_position)) =
 6698                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6699            {
 6700                self.edit_prediction_settings =
 6701                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6702            }
 6703        }
 6704    }
 6705
 6706    fn edit_prediction_settings_at_position(
 6707        &self,
 6708        buffer: &Entity<Buffer>,
 6709        buffer_position: language::Anchor,
 6710        cx: &App,
 6711    ) -> EditPredictionSettings {
 6712        if !self.mode.is_full()
 6713            || !self.show_inline_completions_override.unwrap_or(true)
 6714            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6715        {
 6716            return EditPredictionSettings::Disabled;
 6717        }
 6718
 6719        let buffer = buffer.read(cx);
 6720
 6721        let file = buffer.file();
 6722
 6723        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6724            return EditPredictionSettings::Disabled;
 6725        };
 6726
 6727        let by_provider = matches!(
 6728            self.menu_inline_completions_policy,
 6729            MenuInlineCompletionsPolicy::ByProvider
 6730        );
 6731
 6732        let show_in_menu = by_provider
 6733            && self
 6734                .edit_prediction_provider
 6735                .as_ref()
 6736                .map_or(false, |provider| {
 6737                    provider.provider.show_completions_in_menu()
 6738                });
 6739
 6740        let preview_requires_modifier =
 6741            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6742
 6743        EditPredictionSettings::Enabled {
 6744            show_in_menu,
 6745            preview_requires_modifier,
 6746        }
 6747    }
 6748
 6749    fn should_show_edit_predictions(&self) -> bool {
 6750        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6751    }
 6752
 6753    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6754        matches!(
 6755            self.edit_prediction_preview,
 6756            EditPredictionPreview::Active { .. }
 6757        )
 6758    }
 6759
 6760    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6761        let cursor = self.selections.newest_anchor().head();
 6762        if let Some((buffer, cursor_position)) =
 6763            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6764        {
 6765            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6766        } else {
 6767            false
 6768        }
 6769    }
 6770
 6771    pub fn supports_minimap(&self, cx: &App) -> bool {
 6772        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6773    }
 6774
 6775    fn edit_predictions_enabled_in_buffer(
 6776        &self,
 6777        buffer: &Entity<Buffer>,
 6778        buffer_position: language::Anchor,
 6779        cx: &App,
 6780    ) -> bool {
 6781        maybe!({
 6782            if self.read_only(cx) {
 6783                return Some(false);
 6784            }
 6785            let provider = self.edit_prediction_provider()?;
 6786            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6787                return Some(false);
 6788            }
 6789            let buffer = buffer.read(cx);
 6790            let Some(file) = buffer.file() else {
 6791                return Some(true);
 6792            };
 6793            let settings = all_language_settings(Some(file), cx);
 6794            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6795        })
 6796        .unwrap_or(false)
 6797    }
 6798
 6799    fn cycle_inline_completion(
 6800        &mut self,
 6801        direction: Direction,
 6802        window: &mut Window,
 6803        cx: &mut Context<Self>,
 6804    ) -> Option<()> {
 6805        let provider = self.edit_prediction_provider()?;
 6806        let cursor = self.selections.newest_anchor().head();
 6807        let (buffer, cursor_buffer_position) =
 6808            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6809        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6810            return None;
 6811        }
 6812
 6813        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6814        self.update_visible_inline_completion(window, cx);
 6815
 6816        Some(())
 6817    }
 6818
 6819    pub fn show_inline_completion(
 6820        &mut self,
 6821        _: &ShowEditPrediction,
 6822        window: &mut Window,
 6823        cx: &mut Context<Self>,
 6824    ) {
 6825        if !self.has_active_inline_completion() {
 6826            self.refresh_inline_completion(false, true, window, cx);
 6827            return;
 6828        }
 6829
 6830        self.update_visible_inline_completion(window, cx);
 6831    }
 6832
 6833    pub fn display_cursor_names(
 6834        &mut self,
 6835        _: &DisplayCursorNames,
 6836        window: &mut Window,
 6837        cx: &mut Context<Self>,
 6838    ) {
 6839        self.show_cursor_names(window, cx);
 6840    }
 6841
 6842    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6843        self.show_cursor_names = true;
 6844        cx.notify();
 6845        cx.spawn_in(window, async move |this, cx| {
 6846            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6847            this.update(cx, |this, cx| {
 6848                this.show_cursor_names = false;
 6849                cx.notify()
 6850            })
 6851            .ok()
 6852        })
 6853        .detach();
 6854    }
 6855
 6856    pub fn next_edit_prediction(
 6857        &mut self,
 6858        _: &NextEditPrediction,
 6859        window: &mut Window,
 6860        cx: &mut Context<Self>,
 6861    ) {
 6862        if self.has_active_inline_completion() {
 6863            self.cycle_inline_completion(Direction::Next, window, cx);
 6864        } else {
 6865            let is_copilot_disabled = self
 6866                .refresh_inline_completion(false, true, window, cx)
 6867                .is_none();
 6868            if is_copilot_disabled {
 6869                cx.propagate();
 6870            }
 6871        }
 6872    }
 6873
 6874    pub fn previous_edit_prediction(
 6875        &mut self,
 6876        _: &PreviousEditPrediction,
 6877        window: &mut Window,
 6878        cx: &mut Context<Self>,
 6879    ) {
 6880        if self.has_active_inline_completion() {
 6881            self.cycle_inline_completion(Direction::Prev, window, cx);
 6882        } else {
 6883            let is_copilot_disabled = self
 6884                .refresh_inline_completion(false, true, window, cx)
 6885                .is_none();
 6886            if is_copilot_disabled {
 6887                cx.propagate();
 6888            }
 6889        }
 6890    }
 6891
 6892    pub fn accept_edit_prediction(
 6893        &mut self,
 6894        _: &AcceptEditPrediction,
 6895        window: &mut Window,
 6896        cx: &mut Context<Self>,
 6897    ) {
 6898        if self.show_edit_predictions_in_menu() {
 6899            self.hide_context_menu(window, cx);
 6900        }
 6901
 6902        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6903            return;
 6904        };
 6905
 6906        self.report_inline_completion_event(
 6907            active_inline_completion.completion_id.clone(),
 6908            true,
 6909            cx,
 6910        );
 6911
 6912        match &active_inline_completion.completion {
 6913            InlineCompletion::Move { target, .. } => {
 6914                let target = *target;
 6915
 6916                if let Some(position_map) = &self.last_position_map {
 6917                    if position_map
 6918                        .visible_row_range
 6919                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6920                        || !self.edit_prediction_requires_modifier()
 6921                    {
 6922                        self.unfold_ranges(&[target..target], true, false, cx);
 6923                        // Note that this is also done in vim's handler of the Tab action.
 6924                        self.change_selections(
 6925                            Some(Autoscroll::newest()),
 6926                            window,
 6927                            cx,
 6928                            |selections| {
 6929                                selections.select_anchor_ranges([target..target]);
 6930                            },
 6931                        );
 6932                        self.clear_row_highlights::<EditPredictionPreview>();
 6933
 6934                        self.edit_prediction_preview
 6935                            .set_previous_scroll_position(None);
 6936                    } else {
 6937                        self.edit_prediction_preview
 6938                            .set_previous_scroll_position(Some(
 6939                                position_map.snapshot.scroll_anchor,
 6940                            ));
 6941
 6942                        self.highlight_rows::<EditPredictionPreview>(
 6943                            target..target,
 6944                            cx.theme().colors().editor_highlighted_line_background,
 6945                            RowHighlightOptions {
 6946                                autoscroll: true,
 6947                                ..Default::default()
 6948                            },
 6949                            cx,
 6950                        );
 6951                        self.request_autoscroll(Autoscroll::fit(), cx);
 6952                    }
 6953                }
 6954            }
 6955            InlineCompletion::Edit { edits, .. } => {
 6956                if let Some(provider) = self.edit_prediction_provider() {
 6957                    provider.accept(cx);
 6958                }
 6959
 6960                // Store the transaction ID and selections before applying the edit
 6961                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6962
 6963                let snapshot = self.buffer.read(cx).snapshot(cx);
 6964                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6965
 6966                self.buffer.update(cx, |buffer, cx| {
 6967                    buffer.edit(edits.iter().cloned(), None, cx)
 6968                });
 6969
 6970                self.change_selections(None, window, cx, |s| {
 6971                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6972                });
 6973
 6974                let selections = self.selections.disjoint_anchors();
 6975                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6976                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6977                    if has_new_transaction {
 6978                        self.selection_history
 6979                            .insert_transaction(transaction_id_now, selections);
 6980                    }
 6981                }
 6982
 6983                self.update_visible_inline_completion(window, cx);
 6984                if self.active_inline_completion.is_none() {
 6985                    self.refresh_inline_completion(true, true, window, cx);
 6986                }
 6987
 6988                cx.notify();
 6989            }
 6990        }
 6991
 6992        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6993    }
 6994
 6995    pub fn accept_partial_inline_completion(
 6996        &mut self,
 6997        _: &AcceptPartialEditPrediction,
 6998        window: &mut Window,
 6999        cx: &mut Context<Self>,
 7000    ) {
 7001        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7002            return;
 7003        };
 7004        if self.selections.count() != 1 {
 7005            return;
 7006        }
 7007
 7008        self.report_inline_completion_event(
 7009            active_inline_completion.completion_id.clone(),
 7010            true,
 7011            cx,
 7012        );
 7013
 7014        match &active_inline_completion.completion {
 7015            InlineCompletion::Move { target, .. } => {
 7016                let target = *target;
 7017                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7018                    selections.select_anchor_ranges([target..target]);
 7019                });
 7020            }
 7021            InlineCompletion::Edit { edits, .. } => {
 7022                // Find an insertion that starts at the cursor position.
 7023                let snapshot = self.buffer.read(cx).snapshot(cx);
 7024                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7025                let insertion = edits.iter().find_map(|(range, text)| {
 7026                    let range = range.to_offset(&snapshot);
 7027                    if range.is_empty() && range.start == cursor_offset {
 7028                        Some(text)
 7029                    } else {
 7030                        None
 7031                    }
 7032                });
 7033
 7034                if let Some(text) = insertion {
 7035                    let mut partial_completion = text
 7036                        .chars()
 7037                        .by_ref()
 7038                        .take_while(|c| c.is_alphabetic())
 7039                        .collect::<String>();
 7040                    if partial_completion.is_empty() {
 7041                        partial_completion = text
 7042                            .chars()
 7043                            .by_ref()
 7044                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7045                            .collect::<String>();
 7046                    }
 7047
 7048                    cx.emit(EditorEvent::InputHandled {
 7049                        utf16_range_to_replace: None,
 7050                        text: partial_completion.clone().into(),
 7051                    });
 7052
 7053                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7054
 7055                    self.refresh_inline_completion(true, true, window, cx);
 7056                    cx.notify();
 7057                } else {
 7058                    self.accept_edit_prediction(&Default::default(), window, cx);
 7059                }
 7060            }
 7061        }
 7062    }
 7063
 7064    fn discard_inline_completion(
 7065        &mut self,
 7066        should_report_inline_completion_event: bool,
 7067        cx: &mut Context<Self>,
 7068    ) -> bool {
 7069        if should_report_inline_completion_event {
 7070            let completion_id = self
 7071                .active_inline_completion
 7072                .as_ref()
 7073                .and_then(|active_completion| active_completion.completion_id.clone());
 7074
 7075            self.report_inline_completion_event(completion_id, false, cx);
 7076        }
 7077
 7078        if let Some(provider) = self.edit_prediction_provider() {
 7079            provider.discard(cx);
 7080        }
 7081
 7082        self.take_active_inline_completion(cx)
 7083    }
 7084
 7085    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7086        let Some(provider) = self.edit_prediction_provider() else {
 7087            return;
 7088        };
 7089
 7090        let Some((_, buffer, _)) = self
 7091            .buffer
 7092            .read(cx)
 7093            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7094        else {
 7095            return;
 7096        };
 7097
 7098        let extension = buffer
 7099            .read(cx)
 7100            .file()
 7101            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7102
 7103        let event_type = match accepted {
 7104            true => "Edit Prediction Accepted",
 7105            false => "Edit Prediction Discarded",
 7106        };
 7107        telemetry::event!(
 7108            event_type,
 7109            provider = provider.name(),
 7110            prediction_id = id,
 7111            suggestion_accepted = accepted,
 7112            file_extension = extension,
 7113        );
 7114    }
 7115
 7116    pub fn has_active_inline_completion(&self) -> bool {
 7117        self.active_inline_completion.is_some()
 7118    }
 7119
 7120    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7121        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7122            return false;
 7123        };
 7124
 7125        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7126        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7127        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7128        true
 7129    }
 7130
 7131    /// Returns true when we're displaying the edit prediction popover below the cursor
 7132    /// like we are not previewing and the LSP autocomplete menu is visible
 7133    /// or we are in `when_holding_modifier` mode.
 7134    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7135        if self.edit_prediction_preview_is_active()
 7136            || !self.show_edit_predictions_in_menu()
 7137            || !self.edit_predictions_enabled()
 7138        {
 7139            return false;
 7140        }
 7141
 7142        if self.has_visible_completions_menu() {
 7143            return true;
 7144        }
 7145
 7146        has_completion && self.edit_prediction_requires_modifier()
 7147    }
 7148
 7149    fn handle_modifiers_changed(
 7150        &mut self,
 7151        modifiers: Modifiers,
 7152        position_map: &PositionMap,
 7153        window: &mut Window,
 7154        cx: &mut Context<Self>,
 7155    ) {
 7156        if self.show_edit_predictions_in_menu() {
 7157            self.update_edit_prediction_preview(&modifiers, window, cx);
 7158        }
 7159
 7160        self.update_selection_mode(&modifiers, position_map, window, cx);
 7161
 7162        let mouse_position = window.mouse_position();
 7163        if !position_map.text_hitbox.is_hovered(window) {
 7164            return;
 7165        }
 7166
 7167        self.update_hovered_link(
 7168            position_map.point_for_position(mouse_position),
 7169            &position_map.snapshot,
 7170            modifiers,
 7171            window,
 7172            cx,
 7173        )
 7174    }
 7175
 7176    fn multi_cursor_modifier(
 7177        cursor_event: bool,
 7178        modifiers: &Modifiers,
 7179        cx: &mut Context<Self>,
 7180    ) -> bool {
 7181        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7182        if cursor_event {
 7183            match multi_cursor_setting {
 7184                MultiCursorModifier::Alt => modifiers.alt,
 7185                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7186            }
 7187        } else {
 7188            match multi_cursor_setting {
 7189                MultiCursorModifier::Alt => modifiers.secondary(),
 7190                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7191            }
 7192        }
 7193    }
 7194
 7195    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7196        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7197    }
 7198
 7199    fn update_selection_mode(
 7200        &mut self,
 7201        modifiers: &Modifiers,
 7202        position_map: &PositionMap,
 7203        window: &mut Window,
 7204        cx: &mut Context<Self>,
 7205    ) {
 7206        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7207        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7208            || self.selections.pending.is_none()
 7209        {
 7210            return;
 7211        }
 7212
 7213        let mouse_position = window.mouse_position();
 7214        let point_for_position = position_map.point_for_position(mouse_position);
 7215        let position = point_for_position.previous_valid;
 7216
 7217        self.select(
 7218            SelectPhase::BeginColumnar {
 7219                position,
 7220                reset: false,
 7221                goal_column: point_for_position.exact_unclipped.column(),
 7222            },
 7223            window,
 7224            cx,
 7225        );
 7226    }
 7227
 7228    fn update_edit_prediction_preview(
 7229        &mut self,
 7230        modifiers: &Modifiers,
 7231        window: &mut Window,
 7232        cx: &mut Context<Self>,
 7233    ) {
 7234        let mut modifiers_held = false;
 7235        if let Some(accept_keystroke) = self
 7236            .accept_edit_prediction_keybind(false, window, cx)
 7237            .keystroke()
 7238        {
 7239            modifiers_held = modifiers_held
 7240                || (&accept_keystroke.modifiers == modifiers
 7241                    && accept_keystroke.modifiers.modified());
 7242        };
 7243        if let Some(accept_partial_keystroke) = self
 7244            .accept_edit_prediction_keybind(true, window, cx)
 7245            .keystroke()
 7246        {
 7247            modifiers_held = modifiers_held
 7248                || (&accept_partial_keystroke.modifiers == modifiers
 7249                    && accept_partial_keystroke.modifiers.modified());
 7250        }
 7251
 7252        if modifiers_held {
 7253            if matches!(
 7254                self.edit_prediction_preview,
 7255                EditPredictionPreview::Inactive { .. }
 7256            ) {
 7257                self.edit_prediction_preview = EditPredictionPreview::Active {
 7258                    previous_scroll_position: None,
 7259                    since: Instant::now(),
 7260                };
 7261
 7262                self.update_visible_inline_completion(window, cx);
 7263                cx.notify();
 7264            }
 7265        } else if let EditPredictionPreview::Active {
 7266            previous_scroll_position,
 7267            since,
 7268        } = self.edit_prediction_preview
 7269        {
 7270            if let (Some(previous_scroll_position), Some(position_map)) =
 7271                (previous_scroll_position, self.last_position_map.as_ref())
 7272            {
 7273                self.set_scroll_position(
 7274                    previous_scroll_position
 7275                        .scroll_position(&position_map.snapshot.display_snapshot),
 7276                    window,
 7277                    cx,
 7278                );
 7279            }
 7280
 7281            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7282                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7283            };
 7284            self.clear_row_highlights::<EditPredictionPreview>();
 7285            self.update_visible_inline_completion(window, cx);
 7286            cx.notify();
 7287        }
 7288    }
 7289
 7290    fn update_visible_inline_completion(
 7291        &mut self,
 7292        _window: &mut Window,
 7293        cx: &mut Context<Self>,
 7294    ) -> Option<()> {
 7295        let selection = self.selections.newest_anchor();
 7296        let cursor = selection.head();
 7297        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7298        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7299        let excerpt_id = cursor.excerpt_id;
 7300
 7301        let show_in_menu = self.show_edit_predictions_in_menu();
 7302        let completions_menu_has_precedence = !show_in_menu
 7303            && (self.context_menu.borrow().is_some()
 7304                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7305
 7306        if completions_menu_has_precedence
 7307            || !offset_selection.is_empty()
 7308            || self
 7309                .active_inline_completion
 7310                .as_ref()
 7311                .map_or(false, |completion| {
 7312                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7313                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7314                    !invalidation_range.contains(&offset_selection.head())
 7315                })
 7316        {
 7317            self.discard_inline_completion(false, cx);
 7318            return None;
 7319        }
 7320
 7321        self.take_active_inline_completion(cx);
 7322        let Some(provider) = self.edit_prediction_provider() else {
 7323            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7324            return None;
 7325        };
 7326
 7327        let (buffer, cursor_buffer_position) =
 7328            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7329
 7330        self.edit_prediction_settings =
 7331            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7332
 7333        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7334
 7335        if self.edit_prediction_indent_conflict {
 7336            let cursor_point = cursor.to_point(&multibuffer);
 7337
 7338            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7339
 7340            if let Some((_, indent)) = indents.iter().next() {
 7341                if indent.len == cursor_point.column {
 7342                    self.edit_prediction_indent_conflict = false;
 7343                }
 7344            }
 7345        }
 7346
 7347        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7348        let edits = inline_completion
 7349            .edits
 7350            .into_iter()
 7351            .flat_map(|(range, new_text)| {
 7352                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7353                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7354                Some((start..end, new_text))
 7355            })
 7356            .collect::<Vec<_>>();
 7357        if edits.is_empty() {
 7358            return None;
 7359        }
 7360
 7361        let first_edit_start = edits.first().unwrap().0.start;
 7362        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7363        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7364
 7365        let last_edit_end = edits.last().unwrap().0.end;
 7366        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7367        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7368
 7369        let cursor_row = cursor.to_point(&multibuffer).row;
 7370
 7371        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7372
 7373        let mut inlay_ids = Vec::new();
 7374        let invalidation_row_range;
 7375        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7376            Some(cursor_row..edit_end_row)
 7377        } else if cursor_row > edit_end_row {
 7378            Some(edit_start_row..cursor_row)
 7379        } else {
 7380            None
 7381        };
 7382        let is_move =
 7383            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7384        let completion = if is_move {
 7385            invalidation_row_range =
 7386                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7387            let target = first_edit_start;
 7388            InlineCompletion::Move { target, snapshot }
 7389        } else {
 7390            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7391                && !self.inline_completions_hidden_for_vim_mode;
 7392
 7393            if show_completions_in_buffer {
 7394                if edits
 7395                    .iter()
 7396                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7397                {
 7398                    let mut inlays = Vec::new();
 7399                    for (range, new_text) in &edits {
 7400                        let inlay = Inlay::inline_completion(
 7401                            post_inc(&mut self.next_inlay_id),
 7402                            range.start,
 7403                            new_text.as_str(),
 7404                        );
 7405                        inlay_ids.push(inlay.id);
 7406                        inlays.push(inlay);
 7407                    }
 7408
 7409                    self.splice_inlays(&[], inlays, cx);
 7410                } else {
 7411                    let background_color = cx.theme().status().deleted_background;
 7412                    self.highlight_text::<InlineCompletionHighlight>(
 7413                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7414                        HighlightStyle {
 7415                            background_color: Some(background_color),
 7416                            ..Default::default()
 7417                        },
 7418                        cx,
 7419                    );
 7420                }
 7421            }
 7422
 7423            invalidation_row_range = edit_start_row..edit_end_row;
 7424
 7425            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7426                if provider.show_tab_accept_marker() {
 7427                    EditDisplayMode::TabAccept
 7428                } else {
 7429                    EditDisplayMode::Inline
 7430                }
 7431            } else {
 7432                EditDisplayMode::DiffPopover
 7433            };
 7434
 7435            InlineCompletion::Edit {
 7436                edits,
 7437                edit_preview: inline_completion.edit_preview,
 7438                display_mode,
 7439                snapshot,
 7440            }
 7441        };
 7442
 7443        let invalidation_range = multibuffer
 7444            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7445            ..multibuffer.anchor_after(Point::new(
 7446                invalidation_row_range.end,
 7447                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7448            ));
 7449
 7450        self.stale_inline_completion_in_menu = None;
 7451        self.active_inline_completion = Some(InlineCompletionState {
 7452            inlay_ids,
 7453            completion,
 7454            completion_id: inline_completion.id,
 7455            invalidation_range,
 7456        });
 7457
 7458        cx.notify();
 7459
 7460        Some(())
 7461    }
 7462
 7463    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7464        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7465    }
 7466
 7467    fn clear_tasks(&mut self) {
 7468        self.tasks.clear()
 7469    }
 7470
 7471    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7472        if self.tasks.insert(key, value).is_some() {
 7473            // This case should hopefully be rare, but just in case...
 7474            log::error!(
 7475                "multiple different run targets found on a single line, only the last target will be rendered"
 7476            )
 7477        }
 7478    }
 7479
 7480    /// Get all display points of breakpoints that will be rendered within editor
 7481    ///
 7482    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7483    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7484    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7485    fn active_breakpoints(
 7486        &self,
 7487        range: Range<DisplayRow>,
 7488        window: &mut Window,
 7489        cx: &mut Context<Self>,
 7490    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7491        let mut breakpoint_display_points = HashMap::default();
 7492
 7493        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7494            return breakpoint_display_points;
 7495        };
 7496
 7497        let snapshot = self.snapshot(window, cx);
 7498
 7499        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7500        let Some(project) = self.project.as_ref() else {
 7501            return breakpoint_display_points;
 7502        };
 7503
 7504        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7505            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7506
 7507        for (buffer_snapshot, range, excerpt_id) in
 7508            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7509        {
 7510            let Some(buffer) = project
 7511                .read(cx)
 7512                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7513            else {
 7514                continue;
 7515            };
 7516            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7517                &buffer,
 7518                Some(
 7519                    buffer_snapshot.anchor_before(range.start)
 7520                        ..buffer_snapshot.anchor_after(range.end),
 7521                ),
 7522                buffer_snapshot,
 7523                cx,
 7524            );
 7525            for (breakpoint, state) in breakpoints {
 7526                let multi_buffer_anchor =
 7527                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7528                let position = multi_buffer_anchor
 7529                    .to_point(&multi_buffer_snapshot)
 7530                    .to_display_point(&snapshot);
 7531
 7532                breakpoint_display_points.insert(
 7533                    position.row(),
 7534                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7535                );
 7536            }
 7537        }
 7538
 7539        breakpoint_display_points
 7540    }
 7541
 7542    fn breakpoint_context_menu(
 7543        &self,
 7544        anchor: Anchor,
 7545        window: &mut Window,
 7546        cx: &mut Context<Self>,
 7547    ) -> Entity<ui::ContextMenu> {
 7548        let weak_editor = cx.weak_entity();
 7549        let focus_handle = self.focus_handle(cx);
 7550
 7551        let row = self
 7552            .buffer
 7553            .read(cx)
 7554            .snapshot(cx)
 7555            .summary_for_anchor::<Point>(&anchor)
 7556            .row;
 7557
 7558        let breakpoint = self
 7559            .breakpoint_at_row(row, window, cx)
 7560            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7561
 7562        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7563            "Edit Log Breakpoint"
 7564        } else {
 7565            "Set Log Breakpoint"
 7566        };
 7567
 7568        let condition_breakpoint_msg = if breakpoint
 7569            .as_ref()
 7570            .is_some_and(|bp| bp.1.condition.is_some())
 7571        {
 7572            "Edit Condition Breakpoint"
 7573        } else {
 7574            "Set Condition Breakpoint"
 7575        };
 7576
 7577        let hit_condition_breakpoint_msg = if breakpoint
 7578            .as_ref()
 7579            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7580        {
 7581            "Edit Hit Condition Breakpoint"
 7582        } else {
 7583            "Set Hit Condition Breakpoint"
 7584        };
 7585
 7586        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7587            "Unset Breakpoint"
 7588        } else {
 7589            "Set Breakpoint"
 7590        };
 7591
 7592        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7593
 7594        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7595            BreakpointState::Enabled => Some("Disable"),
 7596            BreakpointState::Disabled => Some("Enable"),
 7597        });
 7598
 7599        let (anchor, breakpoint) =
 7600            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7601
 7602        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7603            menu.on_blur_subscription(Subscription::new(|| {}))
 7604                .context(focus_handle)
 7605                .when(run_to_cursor, |this| {
 7606                    let weak_editor = weak_editor.clone();
 7607                    this.entry("Run to cursor", None, move |window, cx| {
 7608                        weak_editor
 7609                            .update(cx, |editor, cx| {
 7610                                editor.change_selections(None, window, cx, |s| {
 7611                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7612                                });
 7613                            })
 7614                            .ok();
 7615
 7616                        window.dispatch_action(Box::new(RunToCursor), cx);
 7617                    })
 7618                    .separator()
 7619                })
 7620                .when_some(toggle_state_msg, |this, msg| {
 7621                    this.entry(msg, None, {
 7622                        let weak_editor = weak_editor.clone();
 7623                        let breakpoint = breakpoint.clone();
 7624                        move |_window, cx| {
 7625                            weak_editor
 7626                                .update(cx, |this, cx| {
 7627                                    this.edit_breakpoint_at_anchor(
 7628                                        anchor,
 7629                                        breakpoint.as_ref().clone(),
 7630                                        BreakpointEditAction::InvertState,
 7631                                        cx,
 7632                                    );
 7633                                })
 7634                                .log_err();
 7635                        }
 7636                    })
 7637                })
 7638                .entry(set_breakpoint_msg, None, {
 7639                    let weak_editor = weak_editor.clone();
 7640                    let breakpoint = breakpoint.clone();
 7641                    move |_window, cx| {
 7642                        weak_editor
 7643                            .update(cx, |this, cx| {
 7644                                this.edit_breakpoint_at_anchor(
 7645                                    anchor,
 7646                                    breakpoint.as_ref().clone(),
 7647                                    BreakpointEditAction::Toggle,
 7648                                    cx,
 7649                                );
 7650                            })
 7651                            .log_err();
 7652                    }
 7653                })
 7654                .entry(log_breakpoint_msg, None, {
 7655                    let breakpoint = breakpoint.clone();
 7656                    let weak_editor = weak_editor.clone();
 7657                    move |window, cx| {
 7658                        weak_editor
 7659                            .update(cx, |this, cx| {
 7660                                this.add_edit_breakpoint_block(
 7661                                    anchor,
 7662                                    breakpoint.as_ref(),
 7663                                    BreakpointPromptEditAction::Log,
 7664                                    window,
 7665                                    cx,
 7666                                );
 7667                            })
 7668                            .log_err();
 7669                    }
 7670                })
 7671                .entry(condition_breakpoint_msg, None, {
 7672                    let breakpoint = breakpoint.clone();
 7673                    let weak_editor = weak_editor.clone();
 7674                    move |window, cx| {
 7675                        weak_editor
 7676                            .update(cx, |this, cx| {
 7677                                this.add_edit_breakpoint_block(
 7678                                    anchor,
 7679                                    breakpoint.as_ref(),
 7680                                    BreakpointPromptEditAction::Condition,
 7681                                    window,
 7682                                    cx,
 7683                                );
 7684                            })
 7685                            .log_err();
 7686                    }
 7687                })
 7688                .entry(hit_condition_breakpoint_msg, None, 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::HitCondition,
 7695                                window,
 7696                                cx,
 7697                            );
 7698                        })
 7699                        .log_err();
 7700                })
 7701        })
 7702    }
 7703
 7704    fn render_breakpoint(
 7705        &self,
 7706        position: Anchor,
 7707        row: DisplayRow,
 7708        breakpoint: &Breakpoint,
 7709        state: Option<BreakpointSessionState>,
 7710        cx: &mut Context<Self>,
 7711    ) -> IconButton {
 7712        let is_rejected = state.is_some_and(|s| !s.verified);
 7713        // Is it a breakpoint that shows up when hovering over gutter?
 7714        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7715            (false, false),
 7716            |PhantomBreakpointIndicator {
 7717                 is_active,
 7718                 display_row,
 7719                 collides_with_existing_breakpoint,
 7720             }| {
 7721                (
 7722                    is_active && display_row == row,
 7723                    collides_with_existing_breakpoint,
 7724                )
 7725            },
 7726        );
 7727
 7728        let (color, icon) = {
 7729            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7730                (false, false) => ui::IconName::DebugBreakpoint,
 7731                (true, false) => ui::IconName::DebugLogBreakpoint,
 7732                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7733                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7734            };
 7735
 7736            let color = if is_phantom {
 7737                Color::Hint
 7738            } else if is_rejected {
 7739                Color::Disabled
 7740            } else {
 7741                Color::Debugger
 7742            };
 7743
 7744            (color, icon)
 7745        };
 7746
 7747        let breakpoint = Arc::from(breakpoint.clone());
 7748
 7749        let alt_as_text = gpui::Keystroke {
 7750            modifiers: Modifiers::secondary_key(),
 7751            ..Default::default()
 7752        };
 7753        let primary_action_text = if breakpoint.is_disabled() {
 7754            "Enable breakpoint"
 7755        } else if is_phantom && !collides_with_existing {
 7756            "Set breakpoint"
 7757        } else {
 7758            "Unset breakpoint"
 7759        };
 7760        let focus_handle = self.focus_handle.clone();
 7761
 7762        let meta = if is_rejected {
 7763            SharedString::from("No executable code is associated with this line.")
 7764        } else if collides_with_existing && !breakpoint.is_disabled() {
 7765            SharedString::from(format!(
 7766                "{alt_as_text}-click to disable,\nright-click for more options."
 7767            ))
 7768        } else {
 7769            SharedString::from("Right-click for more options.")
 7770        };
 7771        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7772            .icon_size(IconSize::XSmall)
 7773            .size(ui::ButtonSize::None)
 7774            .when(is_rejected, |this| {
 7775                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7776            })
 7777            .icon_color(color)
 7778            .style(ButtonStyle::Transparent)
 7779            .on_click(cx.listener({
 7780                let breakpoint = breakpoint.clone();
 7781
 7782                move |editor, event: &ClickEvent, window, cx| {
 7783                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7784                        BreakpointEditAction::InvertState
 7785                    } else {
 7786                        BreakpointEditAction::Toggle
 7787                    };
 7788
 7789                    window.focus(&editor.focus_handle(cx));
 7790                    editor.edit_breakpoint_at_anchor(
 7791                        position,
 7792                        breakpoint.as_ref().clone(),
 7793                        edit_action,
 7794                        cx,
 7795                    );
 7796                }
 7797            }))
 7798            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7799                editor.set_breakpoint_context_menu(
 7800                    row,
 7801                    Some(position),
 7802                    event.down.position,
 7803                    window,
 7804                    cx,
 7805                );
 7806            }))
 7807            .tooltip(move |window, cx| {
 7808                Tooltip::with_meta_in(
 7809                    primary_action_text,
 7810                    Some(&ToggleBreakpoint),
 7811                    meta.clone(),
 7812                    &focus_handle,
 7813                    window,
 7814                    cx,
 7815                )
 7816            })
 7817    }
 7818
 7819    fn build_tasks_context(
 7820        project: &Entity<Project>,
 7821        buffer: &Entity<Buffer>,
 7822        buffer_row: u32,
 7823        tasks: &Arc<RunnableTasks>,
 7824        cx: &mut Context<Self>,
 7825    ) -> Task<Option<task::TaskContext>> {
 7826        let position = Point::new(buffer_row, tasks.column);
 7827        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7828        let location = Location {
 7829            buffer: buffer.clone(),
 7830            range: range_start..range_start,
 7831        };
 7832        // Fill in the environmental variables from the tree-sitter captures
 7833        let mut captured_task_variables = TaskVariables::default();
 7834        for (capture_name, value) in tasks.extra_variables.clone() {
 7835            captured_task_variables.insert(
 7836                task::VariableName::Custom(capture_name.into()),
 7837                value.clone(),
 7838            );
 7839        }
 7840        project.update(cx, |project, cx| {
 7841            project.task_store().update(cx, |task_store, cx| {
 7842                task_store.task_context_for_location(captured_task_variables, location, cx)
 7843            })
 7844        })
 7845    }
 7846
 7847    pub fn spawn_nearest_task(
 7848        &mut self,
 7849        action: &SpawnNearestTask,
 7850        window: &mut Window,
 7851        cx: &mut Context<Self>,
 7852    ) {
 7853        let Some((workspace, _)) = self.workspace.clone() else {
 7854            return;
 7855        };
 7856        let Some(project) = self.project.clone() else {
 7857            return;
 7858        };
 7859
 7860        // Try to find a closest, enclosing node using tree-sitter that has a
 7861        // task
 7862        let Some((buffer, buffer_row, tasks)) = self
 7863            .find_enclosing_node_task(cx)
 7864            // Or find the task that's closest in row-distance.
 7865            .or_else(|| self.find_closest_task(cx))
 7866        else {
 7867            return;
 7868        };
 7869
 7870        let reveal_strategy = action.reveal;
 7871        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7872        cx.spawn_in(window, async move |_, cx| {
 7873            let context = task_context.await?;
 7874            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7875
 7876            let resolved = &mut resolved_task.resolved;
 7877            resolved.reveal = reveal_strategy;
 7878
 7879            workspace
 7880                .update_in(cx, |workspace, window, cx| {
 7881                    workspace.schedule_resolved_task(
 7882                        task_source_kind,
 7883                        resolved_task,
 7884                        false,
 7885                        window,
 7886                        cx,
 7887                    );
 7888                })
 7889                .ok()
 7890        })
 7891        .detach();
 7892    }
 7893
 7894    fn find_closest_task(
 7895        &mut self,
 7896        cx: &mut Context<Self>,
 7897    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7898        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7899
 7900        let ((buffer_id, row), tasks) = self
 7901            .tasks
 7902            .iter()
 7903            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7904
 7905        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7906        let tasks = Arc::new(tasks.to_owned());
 7907        Some((buffer, *row, tasks))
 7908    }
 7909
 7910    fn find_enclosing_node_task(
 7911        &mut self,
 7912        cx: &mut Context<Self>,
 7913    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7914        let snapshot = self.buffer.read(cx).snapshot(cx);
 7915        let offset = self.selections.newest::<usize>(cx).head();
 7916        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7917        let buffer_id = excerpt.buffer().remote_id();
 7918
 7919        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7920        let mut cursor = layer.node().walk();
 7921
 7922        while cursor.goto_first_child_for_byte(offset).is_some() {
 7923            if cursor.node().end_byte() == offset {
 7924                cursor.goto_next_sibling();
 7925            }
 7926        }
 7927
 7928        // Ascend to the smallest ancestor that contains the range and has a task.
 7929        loop {
 7930            let node = cursor.node();
 7931            let node_range = node.byte_range();
 7932            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7933
 7934            // Check if this node contains our offset
 7935            if node_range.start <= offset && node_range.end >= offset {
 7936                // If it contains offset, check for task
 7937                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7938                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7939                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7940                }
 7941            }
 7942
 7943            if !cursor.goto_parent() {
 7944                break;
 7945            }
 7946        }
 7947        None
 7948    }
 7949
 7950    fn render_run_indicator(
 7951        &self,
 7952        _style: &EditorStyle,
 7953        is_active: bool,
 7954        row: DisplayRow,
 7955        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7956        cx: &mut Context<Self>,
 7957    ) -> IconButton {
 7958        let color = Color::Muted;
 7959        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7960
 7961        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7962            .shape(ui::IconButtonShape::Square)
 7963            .icon_size(IconSize::XSmall)
 7964            .icon_color(color)
 7965            .toggle_state(is_active)
 7966            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7967                let quick_launch = e.down.button == MouseButton::Left;
 7968                window.focus(&editor.focus_handle(cx));
 7969                editor.toggle_code_actions(
 7970                    &ToggleCodeActions {
 7971                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7972                        quick_launch,
 7973                    },
 7974                    window,
 7975                    cx,
 7976                );
 7977            }))
 7978            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7979                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7980            }))
 7981    }
 7982
 7983    pub fn context_menu_visible(&self) -> bool {
 7984        !self.edit_prediction_preview_is_active()
 7985            && self
 7986                .context_menu
 7987                .borrow()
 7988                .as_ref()
 7989                .map_or(false, |menu| menu.visible())
 7990    }
 7991
 7992    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7993        self.context_menu
 7994            .borrow()
 7995            .as_ref()
 7996            .map(|menu| menu.origin())
 7997    }
 7998
 7999    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8000        self.context_menu_options = Some(options);
 8001    }
 8002
 8003    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8004    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8005
 8006    fn render_edit_prediction_popover(
 8007        &mut self,
 8008        text_bounds: &Bounds<Pixels>,
 8009        content_origin: gpui::Point<Pixels>,
 8010        right_margin: Pixels,
 8011        editor_snapshot: &EditorSnapshot,
 8012        visible_row_range: Range<DisplayRow>,
 8013        scroll_top: f32,
 8014        scroll_bottom: f32,
 8015        line_layouts: &[LineWithInvisibles],
 8016        line_height: Pixels,
 8017        scroll_pixel_position: gpui::Point<Pixels>,
 8018        newest_selection_head: Option<DisplayPoint>,
 8019        editor_width: Pixels,
 8020        style: &EditorStyle,
 8021        window: &mut Window,
 8022        cx: &mut App,
 8023    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8024        if self.mode().is_minimap() {
 8025            return None;
 8026        }
 8027        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8028
 8029        if self.edit_prediction_visible_in_cursor_popover(true) {
 8030            return None;
 8031        }
 8032
 8033        match &active_inline_completion.completion {
 8034            InlineCompletion::Move { target, .. } => {
 8035                let target_display_point = target.to_display_point(editor_snapshot);
 8036
 8037                if self.edit_prediction_requires_modifier() {
 8038                    if !self.edit_prediction_preview_is_active() {
 8039                        return None;
 8040                    }
 8041
 8042                    self.render_edit_prediction_modifier_jump_popover(
 8043                        text_bounds,
 8044                        content_origin,
 8045                        visible_row_range,
 8046                        line_layouts,
 8047                        line_height,
 8048                        scroll_pixel_position,
 8049                        newest_selection_head,
 8050                        target_display_point,
 8051                        window,
 8052                        cx,
 8053                    )
 8054                } else {
 8055                    self.render_edit_prediction_eager_jump_popover(
 8056                        text_bounds,
 8057                        content_origin,
 8058                        editor_snapshot,
 8059                        visible_row_range,
 8060                        scroll_top,
 8061                        scroll_bottom,
 8062                        line_height,
 8063                        scroll_pixel_position,
 8064                        target_display_point,
 8065                        editor_width,
 8066                        window,
 8067                        cx,
 8068                    )
 8069                }
 8070            }
 8071            InlineCompletion::Edit {
 8072                display_mode: EditDisplayMode::Inline,
 8073                ..
 8074            } => None,
 8075            InlineCompletion::Edit {
 8076                display_mode: EditDisplayMode::TabAccept,
 8077                edits,
 8078                ..
 8079            } => {
 8080                let range = &edits.first()?.0;
 8081                let target_display_point = range.end.to_display_point(editor_snapshot);
 8082
 8083                self.render_edit_prediction_end_of_line_popover(
 8084                    "Accept",
 8085                    editor_snapshot,
 8086                    visible_row_range,
 8087                    target_display_point,
 8088                    line_height,
 8089                    scroll_pixel_position,
 8090                    content_origin,
 8091                    editor_width,
 8092                    window,
 8093                    cx,
 8094                )
 8095            }
 8096            InlineCompletion::Edit {
 8097                edits,
 8098                edit_preview,
 8099                display_mode: EditDisplayMode::DiffPopover,
 8100                snapshot,
 8101            } => self.render_edit_prediction_diff_popover(
 8102                text_bounds,
 8103                content_origin,
 8104                right_margin,
 8105                editor_snapshot,
 8106                visible_row_range,
 8107                line_layouts,
 8108                line_height,
 8109                scroll_pixel_position,
 8110                newest_selection_head,
 8111                editor_width,
 8112                style,
 8113                edits,
 8114                edit_preview,
 8115                snapshot,
 8116                window,
 8117                cx,
 8118            ),
 8119        }
 8120    }
 8121
 8122    fn render_edit_prediction_modifier_jump_popover(
 8123        &mut self,
 8124        text_bounds: &Bounds<Pixels>,
 8125        content_origin: gpui::Point<Pixels>,
 8126        visible_row_range: Range<DisplayRow>,
 8127        line_layouts: &[LineWithInvisibles],
 8128        line_height: Pixels,
 8129        scroll_pixel_position: gpui::Point<Pixels>,
 8130        newest_selection_head: Option<DisplayPoint>,
 8131        target_display_point: DisplayPoint,
 8132        window: &mut Window,
 8133        cx: &mut App,
 8134    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8135        let scrolled_content_origin =
 8136            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8137
 8138        const SCROLL_PADDING_Y: Pixels = px(12.);
 8139
 8140        if target_display_point.row() < visible_row_range.start {
 8141            return self.render_edit_prediction_scroll_popover(
 8142                |_| SCROLL_PADDING_Y,
 8143                IconName::ArrowUp,
 8144                visible_row_range,
 8145                line_layouts,
 8146                newest_selection_head,
 8147                scrolled_content_origin,
 8148                window,
 8149                cx,
 8150            );
 8151        } else if target_display_point.row() >= visible_row_range.end {
 8152            return self.render_edit_prediction_scroll_popover(
 8153                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8154                IconName::ArrowDown,
 8155                visible_row_range,
 8156                line_layouts,
 8157                newest_selection_head,
 8158                scrolled_content_origin,
 8159                window,
 8160                cx,
 8161            );
 8162        }
 8163
 8164        const POLE_WIDTH: Pixels = px(2.);
 8165
 8166        let line_layout =
 8167            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8168        let target_column = target_display_point.column() as usize;
 8169
 8170        let target_x = line_layout.x_for_index(target_column);
 8171        let target_y =
 8172            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8173
 8174        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8175
 8176        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8177        border_color.l += 0.001;
 8178
 8179        let mut element = v_flex()
 8180            .items_end()
 8181            .when(flag_on_right, |el| el.items_start())
 8182            .child(if flag_on_right {
 8183                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8184                    .rounded_bl(px(0.))
 8185                    .rounded_tl(px(0.))
 8186                    .border_l_2()
 8187                    .border_color(border_color)
 8188            } else {
 8189                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8190                    .rounded_br(px(0.))
 8191                    .rounded_tr(px(0.))
 8192                    .border_r_2()
 8193                    .border_color(border_color)
 8194            })
 8195            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8196            .into_any();
 8197
 8198        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8199
 8200        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8201            - point(
 8202                if flag_on_right {
 8203                    POLE_WIDTH
 8204                } else {
 8205                    size.width - POLE_WIDTH
 8206                },
 8207                size.height - line_height,
 8208            );
 8209
 8210        origin.x = origin.x.max(content_origin.x);
 8211
 8212        element.prepaint_at(origin, window, cx);
 8213
 8214        Some((element, origin))
 8215    }
 8216
 8217    fn render_edit_prediction_scroll_popover(
 8218        &mut self,
 8219        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8220        scroll_icon: IconName,
 8221        visible_row_range: Range<DisplayRow>,
 8222        line_layouts: &[LineWithInvisibles],
 8223        newest_selection_head: Option<DisplayPoint>,
 8224        scrolled_content_origin: gpui::Point<Pixels>,
 8225        window: &mut Window,
 8226        cx: &mut App,
 8227    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8228        let mut element = self
 8229            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8230            .into_any();
 8231
 8232        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8233
 8234        let cursor = newest_selection_head?;
 8235        let cursor_row_layout =
 8236            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8237        let cursor_column = cursor.column() as usize;
 8238
 8239        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8240
 8241        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8242
 8243        element.prepaint_at(origin, window, cx);
 8244        Some((element, origin))
 8245    }
 8246
 8247    fn render_edit_prediction_eager_jump_popover(
 8248        &mut self,
 8249        text_bounds: &Bounds<Pixels>,
 8250        content_origin: gpui::Point<Pixels>,
 8251        editor_snapshot: &EditorSnapshot,
 8252        visible_row_range: Range<DisplayRow>,
 8253        scroll_top: f32,
 8254        scroll_bottom: f32,
 8255        line_height: Pixels,
 8256        scroll_pixel_position: gpui::Point<Pixels>,
 8257        target_display_point: DisplayPoint,
 8258        editor_width: Pixels,
 8259        window: &mut Window,
 8260        cx: &mut App,
 8261    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8262        if target_display_point.row().as_f32() < scroll_top {
 8263            let mut element = self
 8264                .render_edit_prediction_line_popover(
 8265                    "Jump to Edit",
 8266                    Some(IconName::ArrowUp),
 8267                    window,
 8268                    cx,
 8269                )?
 8270                .into_any();
 8271
 8272            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8273            let offset = point(
 8274                (text_bounds.size.width - size.width) / 2.,
 8275                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8276            );
 8277
 8278            let origin = text_bounds.origin + offset;
 8279            element.prepaint_at(origin, window, cx);
 8280            Some((element, origin))
 8281        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8282            let mut element = self
 8283                .render_edit_prediction_line_popover(
 8284                    "Jump to Edit",
 8285                    Some(IconName::ArrowDown),
 8286                    window,
 8287                    cx,
 8288                )?
 8289                .into_any();
 8290
 8291            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8292            let offset = point(
 8293                (text_bounds.size.width - size.width) / 2.,
 8294                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8295            );
 8296
 8297            let origin = text_bounds.origin + offset;
 8298            element.prepaint_at(origin, window, cx);
 8299            Some((element, origin))
 8300        } else {
 8301            self.render_edit_prediction_end_of_line_popover(
 8302                "Jump to Edit",
 8303                editor_snapshot,
 8304                visible_row_range,
 8305                target_display_point,
 8306                line_height,
 8307                scroll_pixel_position,
 8308                content_origin,
 8309                editor_width,
 8310                window,
 8311                cx,
 8312            )
 8313        }
 8314    }
 8315
 8316    fn render_edit_prediction_end_of_line_popover(
 8317        self: &mut Editor,
 8318        label: &'static str,
 8319        editor_snapshot: &EditorSnapshot,
 8320        visible_row_range: Range<DisplayRow>,
 8321        target_display_point: DisplayPoint,
 8322        line_height: Pixels,
 8323        scroll_pixel_position: gpui::Point<Pixels>,
 8324        content_origin: gpui::Point<Pixels>,
 8325        editor_width: Pixels,
 8326        window: &mut Window,
 8327        cx: &mut App,
 8328    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8329        let target_line_end = DisplayPoint::new(
 8330            target_display_point.row(),
 8331            editor_snapshot.line_len(target_display_point.row()),
 8332        );
 8333
 8334        let mut element = self
 8335            .render_edit_prediction_line_popover(label, None, window, cx)?
 8336            .into_any();
 8337
 8338        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8339
 8340        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8341
 8342        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8343        let mut origin = start_point
 8344            + line_origin
 8345            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8346        origin.x = origin.x.max(content_origin.x);
 8347
 8348        let max_x = content_origin.x + editor_width - size.width;
 8349
 8350        if origin.x > max_x {
 8351            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8352
 8353            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8354                origin.y += offset;
 8355                IconName::ArrowUp
 8356            } else {
 8357                origin.y -= offset;
 8358                IconName::ArrowDown
 8359            };
 8360
 8361            element = self
 8362                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8363                .into_any();
 8364
 8365            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8366
 8367            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8368        }
 8369
 8370        element.prepaint_at(origin, window, cx);
 8371        Some((element, origin))
 8372    }
 8373
 8374    fn render_edit_prediction_diff_popover(
 8375        self: &Editor,
 8376        text_bounds: &Bounds<Pixels>,
 8377        content_origin: gpui::Point<Pixels>,
 8378        right_margin: Pixels,
 8379        editor_snapshot: &EditorSnapshot,
 8380        visible_row_range: Range<DisplayRow>,
 8381        line_layouts: &[LineWithInvisibles],
 8382        line_height: Pixels,
 8383        scroll_pixel_position: gpui::Point<Pixels>,
 8384        newest_selection_head: Option<DisplayPoint>,
 8385        editor_width: Pixels,
 8386        style: &EditorStyle,
 8387        edits: &Vec<(Range<Anchor>, String)>,
 8388        edit_preview: &Option<language::EditPreview>,
 8389        snapshot: &language::BufferSnapshot,
 8390        window: &mut Window,
 8391        cx: &mut App,
 8392    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8393        let edit_start = edits
 8394            .first()
 8395            .unwrap()
 8396            .0
 8397            .start
 8398            .to_display_point(editor_snapshot);
 8399        let edit_end = edits
 8400            .last()
 8401            .unwrap()
 8402            .0
 8403            .end
 8404            .to_display_point(editor_snapshot);
 8405
 8406        let is_visible = visible_row_range.contains(&edit_start.row())
 8407            || visible_row_range.contains(&edit_end.row());
 8408        if !is_visible {
 8409            return None;
 8410        }
 8411
 8412        let highlighted_edits =
 8413            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8414
 8415        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8416        let line_count = highlighted_edits.text.lines().count();
 8417
 8418        const BORDER_WIDTH: Pixels = px(1.);
 8419
 8420        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8421        let has_keybind = keybind.is_some();
 8422
 8423        let mut element = h_flex()
 8424            .items_start()
 8425            .child(
 8426                h_flex()
 8427                    .bg(cx.theme().colors().editor_background)
 8428                    .border(BORDER_WIDTH)
 8429                    .shadow_sm()
 8430                    .border_color(cx.theme().colors().border)
 8431                    .rounded_l_lg()
 8432                    .when(line_count > 1, |el| el.rounded_br_lg())
 8433                    .pr_1()
 8434                    .child(styled_text),
 8435            )
 8436            .child(
 8437                h_flex()
 8438                    .h(line_height + BORDER_WIDTH * 2.)
 8439                    .px_1p5()
 8440                    .gap_1()
 8441                    // Workaround: For some reason, there's a gap if we don't do this
 8442                    .ml(-BORDER_WIDTH)
 8443                    .shadow(vec![gpui::BoxShadow {
 8444                        color: gpui::black().opacity(0.05),
 8445                        offset: point(px(1.), px(1.)),
 8446                        blur_radius: px(2.),
 8447                        spread_radius: px(0.),
 8448                    }])
 8449                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8450                    .border(BORDER_WIDTH)
 8451                    .border_color(cx.theme().colors().border)
 8452                    .rounded_r_lg()
 8453                    .id("edit_prediction_diff_popover_keybind")
 8454                    .when(!has_keybind, |el| {
 8455                        let status_colors = cx.theme().status();
 8456
 8457                        el.bg(status_colors.error_background)
 8458                            .border_color(status_colors.error.opacity(0.6))
 8459                            .child(Icon::new(IconName::Info).color(Color::Error))
 8460                            .cursor_default()
 8461                            .hoverable_tooltip(move |_window, cx| {
 8462                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8463                            })
 8464                    })
 8465                    .children(keybind),
 8466            )
 8467            .into_any();
 8468
 8469        let longest_row =
 8470            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8471        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8472            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8473        } else {
 8474            layout_line(
 8475                longest_row,
 8476                editor_snapshot,
 8477                style,
 8478                editor_width,
 8479                |_| false,
 8480                window,
 8481                cx,
 8482            )
 8483            .width
 8484        };
 8485
 8486        let viewport_bounds =
 8487            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8488                right: -right_margin,
 8489                ..Default::default()
 8490            });
 8491
 8492        let x_after_longest =
 8493            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8494                - scroll_pixel_position.x;
 8495
 8496        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8497
 8498        // Fully visible if it can be displayed within the window (allow overlapping other
 8499        // panes). However, this is only allowed if the popover starts within text_bounds.
 8500        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8501            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8502
 8503        let mut origin = if can_position_to_the_right {
 8504            point(
 8505                x_after_longest,
 8506                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8507                    - scroll_pixel_position.y,
 8508            )
 8509        } else {
 8510            let cursor_row = newest_selection_head.map(|head| head.row());
 8511            let above_edit = edit_start
 8512                .row()
 8513                .0
 8514                .checked_sub(line_count as u32)
 8515                .map(DisplayRow);
 8516            let below_edit = Some(edit_end.row() + 1);
 8517            let above_cursor =
 8518                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8519            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8520
 8521            // Place the edit popover adjacent to the edit if there is a location
 8522            // available that is onscreen and does not obscure the cursor. Otherwise,
 8523            // place it adjacent to the cursor.
 8524            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8525                .into_iter()
 8526                .flatten()
 8527                .find(|&start_row| {
 8528                    let end_row = start_row + line_count as u32;
 8529                    visible_row_range.contains(&start_row)
 8530                        && visible_row_range.contains(&end_row)
 8531                        && cursor_row.map_or(true, |cursor_row| {
 8532                            !((start_row..end_row).contains(&cursor_row))
 8533                        })
 8534                })?;
 8535
 8536            content_origin
 8537                + point(
 8538                    -scroll_pixel_position.x,
 8539                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8540                )
 8541        };
 8542
 8543        origin.x -= BORDER_WIDTH;
 8544
 8545        window.defer_draw(element, origin, 1);
 8546
 8547        // Do not return an element, since it will already be drawn due to defer_draw.
 8548        None
 8549    }
 8550
 8551    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8552        px(30.)
 8553    }
 8554
 8555    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8556        if self.read_only(cx) {
 8557            cx.theme().players().read_only()
 8558        } else {
 8559            self.style.as_ref().unwrap().local_player
 8560        }
 8561    }
 8562
 8563    fn render_edit_prediction_accept_keybind(
 8564        &self,
 8565        window: &mut Window,
 8566        cx: &App,
 8567    ) -> Option<AnyElement> {
 8568        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8569        let accept_keystroke = accept_binding.keystroke()?;
 8570
 8571        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8572
 8573        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8574            Color::Accent
 8575        } else {
 8576            Color::Muted
 8577        };
 8578
 8579        h_flex()
 8580            .px_0p5()
 8581            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8582            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8583            .text_size(TextSize::XSmall.rems(cx))
 8584            .child(h_flex().children(ui::render_modifiers(
 8585                &accept_keystroke.modifiers,
 8586                PlatformStyle::platform(),
 8587                Some(modifiers_color),
 8588                Some(IconSize::XSmall.rems().into()),
 8589                true,
 8590            )))
 8591            .when(is_platform_style_mac, |parent| {
 8592                parent.child(accept_keystroke.key.clone())
 8593            })
 8594            .when(!is_platform_style_mac, |parent| {
 8595                parent.child(
 8596                    Key::new(
 8597                        util::capitalize(&accept_keystroke.key),
 8598                        Some(Color::Default),
 8599                    )
 8600                    .size(Some(IconSize::XSmall.rems().into())),
 8601                )
 8602            })
 8603            .into_any()
 8604            .into()
 8605    }
 8606
 8607    fn render_edit_prediction_line_popover(
 8608        &self,
 8609        label: impl Into<SharedString>,
 8610        icon: Option<IconName>,
 8611        window: &mut Window,
 8612        cx: &App,
 8613    ) -> Option<Stateful<Div>> {
 8614        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8615
 8616        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8617        let has_keybind = keybind.is_some();
 8618
 8619        let result = h_flex()
 8620            .id("ep-line-popover")
 8621            .py_0p5()
 8622            .pl_1()
 8623            .pr(padding_right)
 8624            .gap_1()
 8625            .rounded_md()
 8626            .border_1()
 8627            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8628            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8629            .shadow_sm()
 8630            .when(!has_keybind, |el| {
 8631                let status_colors = cx.theme().status();
 8632
 8633                el.bg(status_colors.error_background)
 8634                    .border_color(status_colors.error.opacity(0.6))
 8635                    .pl_2()
 8636                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8637                    .cursor_default()
 8638                    .hoverable_tooltip(move |_window, cx| {
 8639                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8640                    })
 8641            })
 8642            .children(keybind)
 8643            .child(
 8644                Label::new(label)
 8645                    .size(LabelSize::Small)
 8646                    .when(!has_keybind, |el| {
 8647                        el.color(cx.theme().status().error.into()).strikethrough()
 8648                    }),
 8649            )
 8650            .when(!has_keybind, |el| {
 8651                el.child(
 8652                    h_flex().ml_1().child(
 8653                        Icon::new(IconName::Info)
 8654                            .size(IconSize::Small)
 8655                            .color(cx.theme().status().error.into()),
 8656                    ),
 8657                )
 8658            })
 8659            .when_some(icon, |element, icon| {
 8660                element.child(
 8661                    div()
 8662                        .mt(px(1.5))
 8663                        .child(Icon::new(icon).size(IconSize::Small)),
 8664                )
 8665            });
 8666
 8667        Some(result)
 8668    }
 8669
 8670    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8671        let accent_color = cx.theme().colors().text_accent;
 8672        let editor_bg_color = cx.theme().colors().editor_background;
 8673        editor_bg_color.blend(accent_color.opacity(0.1))
 8674    }
 8675
 8676    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8677        let accent_color = cx.theme().colors().text_accent;
 8678        let editor_bg_color = cx.theme().colors().editor_background;
 8679        editor_bg_color.blend(accent_color.opacity(0.6))
 8680    }
 8681
 8682    fn render_edit_prediction_cursor_popover(
 8683        &self,
 8684        min_width: Pixels,
 8685        max_width: Pixels,
 8686        cursor_point: Point,
 8687        style: &EditorStyle,
 8688        accept_keystroke: Option<&gpui::Keystroke>,
 8689        _window: &Window,
 8690        cx: &mut Context<Editor>,
 8691    ) -> Option<AnyElement> {
 8692        let provider = self.edit_prediction_provider.as_ref()?;
 8693
 8694        if provider.provider.needs_terms_acceptance(cx) {
 8695            return Some(
 8696                h_flex()
 8697                    .min_w(min_width)
 8698                    .flex_1()
 8699                    .px_2()
 8700                    .py_1()
 8701                    .gap_3()
 8702                    .elevation_2(cx)
 8703                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8704                    .id("accept-terms")
 8705                    .cursor_pointer()
 8706                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8707                    .on_click(cx.listener(|this, _event, window, cx| {
 8708                        cx.stop_propagation();
 8709                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8710                        window.dispatch_action(
 8711                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8712                            cx,
 8713                        );
 8714                    }))
 8715                    .child(
 8716                        h_flex()
 8717                            .flex_1()
 8718                            .gap_2()
 8719                            .child(Icon::new(IconName::ZedPredict))
 8720                            .child(Label::new("Accept Terms of Service"))
 8721                            .child(div().w_full())
 8722                            .child(
 8723                                Icon::new(IconName::ArrowUpRight)
 8724                                    .color(Color::Muted)
 8725                                    .size(IconSize::Small),
 8726                            )
 8727                            .into_any_element(),
 8728                    )
 8729                    .into_any(),
 8730            );
 8731        }
 8732
 8733        let is_refreshing = provider.provider.is_refreshing(cx);
 8734
 8735        fn pending_completion_container() -> Div {
 8736            h_flex()
 8737                .h_full()
 8738                .flex_1()
 8739                .gap_2()
 8740                .child(Icon::new(IconName::ZedPredict))
 8741        }
 8742
 8743        let completion = match &self.active_inline_completion {
 8744            Some(prediction) => {
 8745                if !self.has_visible_completions_menu() {
 8746                    const RADIUS: Pixels = px(6.);
 8747                    const BORDER_WIDTH: Pixels = px(1.);
 8748
 8749                    return Some(
 8750                        h_flex()
 8751                            .elevation_2(cx)
 8752                            .border(BORDER_WIDTH)
 8753                            .border_color(cx.theme().colors().border)
 8754                            .when(accept_keystroke.is_none(), |el| {
 8755                                el.border_color(cx.theme().status().error)
 8756                            })
 8757                            .rounded(RADIUS)
 8758                            .rounded_tl(px(0.))
 8759                            .overflow_hidden()
 8760                            .child(div().px_1p5().child(match &prediction.completion {
 8761                                InlineCompletion::Move { target, snapshot } => {
 8762                                    use text::ToPoint as _;
 8763                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8764                                    {
 8765                                        Icon::new(IconName::ZedPredictDown)
 8766                                    } else {
 8767                                        Icon::new(IconName::ZedPredictUp)
 8768                                    }
 8769                                }
 8770                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8771                            }))
 8772                            .child(
 8773                                h_flex()
 8774                                    .gap_1()
 8775                                    .py_1()
 8776                                    .px_2()
 8777                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8778                                    .border_l_1()
 8779                                    .border_color(cx.theme().colors().border)
 8780                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8781                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8782                                        el.child(
 8783                                            Label::new("Hold")
 8784                                                .size(LabelSize::Small)
 8785                                                .when(accept_keystroke.is_none(), |el| {
 8786                                                    el.strikethrough()
 8787                                                })
 8788                                                .line_height_style(LineHeightStyle::UiLabel),
 8789                                        )
 8790                                    })
 8791                                    .id("edit_prediction_cursor_popover_keybind")
 8792                                    .when(accept_keystroke.is_none(), |el| {
 8793                                        let status_colors = cx.theme().status();
 8794
 8795                                        el.bg(status_colors.error_background)
 8796                                            .border_color(status_colors.error.opacity(0.6))
 8797                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8798                                            .cursor_default()
 8799                                            .hoverable_tooltip(move |_window, cx| {
 8800                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8801                                                    .into()
 8802                                            })
 8803                                    })
 8804                                    .when_some(
 8805                                        accept_keystroke.as_ref(),
 8806                                        |el, accept_keystroke| {
 8807                                            el.child(h_flex().children(ui::render_modifiers(
 8808                                                &accept_keystroke.modifiers,
 8809                                                PlatformStyle::platform(),
 8810                                                Some(Color::Default),
 8811                                                Some(IconSize::XSmall.rems().into()),
 8812                                                false,
 8813                                            )))
 8814                                        },
 8815                                    ),
 8816                            )
 8817                            .into_any(),
 8818                    );
 8819                }
 8820
 8821                self.render_edit_prediction_cursor_popover_preview(
 8822                    prediction,
 8823                    cursor_point,
 8824                    style,
 8825                    cx,
 8826                )?
 8827            }
 8828
 8829            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8830                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8831                    stale_completion,
 8832                    cursor_point,
 8833                    style,
 8834                    cx,
 8835                )?,
 8836
 8837                None => {
 8838                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8839                }
 8840            },
 8841
 8842            None => pending_completion_container().child(Label::new("No Prediction")),
 8843        };
 8844
 8845        let completion = if is_refreshing {
 8846            completion
 8847                .with_animation(
 8848                    "loading-completion",
 8849                    Animation::new(Duration::from_secs(2))
 8850                        .repeat()
 8851                        .with_easing(pulsating_between(0.4, 0.8)),
 8852                    |label, delta| label.opacity(delta),
 8853                )
 8854                .into_any_element()
 8855        } else {
 8856            completion.into_any_element()
 8857        };
 8858
 8859        let has_completion = self.active_inline_completion.is_some();
 8860
 8861        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8862        Some(
 8863            h_flex()
 8864                .min_w(min_width)
 8865                .max_w(max_width)
 8866                .flex_1()
 8867                .elevation_2(cx)
 8868                .border_color(cx.theme().colors().border)
 8869                .child(
 8870                    div()
 8871                        .flex_1()
 8872                        .py_1()
 8873                        .px_2()
 8874                        .overflow_hidden()
 8875                        .child(completion),
 8876                )
 8877                .when_some(accept_keystroke, |el, accept_keystroke| {
 8878                    if !accept_keystroke.modifiers.modified() {
 8879                        return el;
 8880                    }
 8881
 8882                    el.child(
 8883                        h_flex()
 8884                            .h_full()
 8885                            .border_l_1()
 8886                            .rounded_r_lg()
 8887                            .border_color(cx.theme().colors().border)
 8888                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8889                            .gap_1()
 8890                            .py_1()
 8891                            .px_2()
 8892                            .child(
 8893                                h_flex()
 8894                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8895                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8896                                    .child(h_flex().children(ui::render_modifiers(
 8897                                        &accept_keystroke.modifiers,
 8898                                        PlatformStyle::platform(),
 8899                                        Some(if !has_completion {
 8900                                            Color::Muted
 8901                                        } else {
 8902                                            Color::Default
 8903                                        }),
 8904                                        None,
 8905                                        false,
 8906                                    ))),
 8907                            )
 8908                            .child(Label::new("Preview").into_any_element())
 8909                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8910                    )
 8911                })
 8912                .into_any(),
 8913        )
 8914    }
 8915
 8916    fn render_edit_prediction_cursor_popover_preview(
 8917        &self,
 8918        completion: &InlineCompletionState,
 8919        cursor_point: Point,
 8920        style: &EditorStyle,
 8921        cx: &mut Context<Editor>,
 8922    ) -> Option<Div> {
 8923        use text::ToPoint as _;
 8924
 8925        fn render_relative_row_jump(
 8926            prefix: impl Into<String>,
 8927            current_row: u32,
 8928            target_row: u32,
 8929        ) -> Div {
 8930            let (row_diff, arrow) = if target_row < current_row {
 8931                (current_row - target_row, IconName::ArrowUp)
 8932            } else {
 8933                (target_row - current_row, IconName::ArrowDown)
 8934            };
 8935
 8936            h_flex()
 8937                .child(
 8938                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8939                        .color(Color::Muted)
 8940                        .size(LabelSize::Small),
 8941                )
 8942                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8943        }
 8944
 8945        match &completion.completion {
 8946            InlineCompletion::Move {
 8947                target, snapshot, ..
 8948            } => Some(
 8949                h_flex()
 8950                    .px_2()
 8951                    .gap_2()
 8952                    .flex_1()
 8953                    .child(
 8954                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8955                            Icon::new(IconName::ZedPredictDown)
 8956                        } else {
 8957                            Icon::new(IconName::ZedPredictUp)
 8958                        },
 8959                    )
 8960                    .child(Label::new("Jump to Edit")),
 8961            ),
 8962
 8963            InlineCompletion::Edit {
 8964                edits,
 8965                edit_preview,
 8966                snapshot,
 8967                display_mode: _,
 8968            } => {
 8969                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8970
 8971                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8972                    &snapshot,
 8973                    &edits,
 8974                    edit_preview.as_ref()?,
 8975                    true,
 8976                    cx,
 8977                )
 8978                .first_line_preview();
 8979
 8980                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8981                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8982
 8983                let preview = h_flex()
 8984                    .gap_1()
 8985                    .min_w_16()
 8986                    .child(styled_text)
 8987                    .when(has_more_lines, |parent| parent.child(""));
 8988
 8989                let left = if first_edit_row != cursor_point.row {
 8990                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8991                        .into_any_element()
 8992                } else {
 8993                    Icon::new(IconName::ZedPredict).into_any_element()
 8994                };
 8995
 8996                Some(
 8997                    h_flex()
 8998                        .h_full()
 8999                        .flex_1()
 9000                        .gap_2()
 9001                        .pr_1()
 9002                        .overflow_x_hidden()
 9003                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9004                        .child(left)
 9005                        .child(preview),
 9006                )
 9007            }
 9008        }
 9009    }
 9010
 9011    pub fn render_context_menu(
 9012        &self,
 9013        style: &EditorStyle,
 9014        max_height_in_lines: u32,
 9015        window: &mut Window,
 9016        cx: &mut Context<Editor>,
 9017    ) -> Option<AnyElement> {
 9018        let menu = self.context_menu.borrow();
 9019        let menu = menu.as_ref()?;
 9020        if !menu.visible() {
 9021            return None;
 9022        };
 9023        Some(menu.render(style, max_height_in_lines, window, cx))
 9024    }
 9025
 9026    fn render_context_menu_aside(
 9027        &mut self,
 9028        max_size: Size<Pixels>,
 9029        window: &mut Window,
 9030        cx: &mut Context<Editor>,
 9031    ) -> Option<AnyElement> {
 9032        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9033            if menu.visible() {
 9034                menu.render_aside(max_size, window, cx)
 9035            } else {
 9036                None
 9037            }
 9038        })
 9039    }
 9040
 9041    fn hide_context_menu(
 9042        &mut self,
 9043        window: &mut Window,
 9044        cx: &mut Context<Self>,
 9045    ) -> Option<CodeContextMenu> {
 9046        cx.notify();
 9047        self.completion_tasks.clear();
 9048        let context_menu = self.context_menu.borrow_mut().take();
 9049        self.stale_inline_completion_in_menu.take();
 9050        self.update_visible_inline_completion(window, cx);
 9051        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9052            if let Some(completion_provider) = &self.completion_provider {
 9053                completion_provider.selection_changed(None, window, cx);
 9054            }
 9055        }
 9056        context_menu
 9057    }
 9058
 9059    fn show_snippet_choices(
 9060        &mut self,
 9061        choices: &Vec<String>,
 9062        selection: Range<Anchor>,
 9063        cx: &mut Context<Self>,
 9064    ) {
 9065        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9066            (Some(a), Some(b)) if a == b => a,
 9067            _ => {
 9068                log::error!("expected anchor range to have matching buffer IDs");
 9069                return;
 9070            }
 9071        };
 9072        let multi_buffer = self.buffer().read(cx);
 9073        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9074            return;
 9075        };
 9076
 9077        let id = post_inc(&mut self.next_completion_id);
 9078        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9079        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9080            CompletionsMenu::new_snippet_choices(
 9081                id,
 9082                true,
 9083                choices,
 9084                selection,
 9085                buffer,
 9086                snippet_sort_order,
 9087            ),
 9088        ));
 9089    }
 9090
 9091    pub fn insert_snippet(
 9092        &mut self,
 9093        insertion_ranges: &[Range<usize>],
 9094        snippet: Snippet,
 9095        window: &mut Window,
 9096        cx: &mut Context<Self>,
 9097    ) -> Result<()> {
 9098        struct Tabstop<T> {
 9099            is_end_tabstop: bool,
 9100            ranges: Vec<Range<T>>,
 9101            choices: Option<Vec<String>>,
 9102        }
 9103
 9104        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9105            let snippet_text: Arc<str> = snippet.text.clone().into();
 9106            let edits = insertion_ranges
 9107                .iter()
 9108                .cloned()
 9109                .map(|range| (range, snippet_text.clone()));
 9110            let autoindent_mode = AutoindentMode::Block {
 9111                original_indent_columns: Vec::new(),
 9112            };
 9113            buffer.edit(edits, Some(autoindent_mode), cx);
 9114
 9115            let snapshot = &*buffer.read(cx);
 9116            let snippet = &snippet;
 9117            snippet
 9118                .tabstops
 9119                .iter()
 9120                .map(|tabstop| {
 9121                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9122                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9123                    });
 9124                    let mut tabstop_ranges = tabstop
 9125                        .ranges
 9126                        .iter()
 9127                        .flat_map(|tabstop_range| {
 9128                            let mut delta = 0_isize;
 9129                            insertion_ranges.iter().map(move |insertion_range| {
 9130                                let insertion_start = insertion_range.start as isize + delta;
 9131                                delta +=
 9132                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9133
 9134                                let start = ((insertion_start + tabstop_range.start) as usize)
 9135                                    .min(snapshot.len());
 9136                                let end = ((insertion_start + tabstop_range.end) as usize)
 9137                                    .min(snapshot.len());
 9138                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9139                            })
 9140                        })
 9141                        .collect::<Vec<_>>();
 9142                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9143
 9144                    Tabstop {
 9145                        is_end_tabstop,
 9146                        ranges: tabstop_ranges,
 9147                        choices: tabstop.choices.clone(),
 9148                    }
 9149                })
 9150                .collect::<Vec<_>>()
 9151        });
 9152        if let Some(tabstop) = tabstops.first() {
 9153            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9154                // Reverse order so that the first range is the newest created selection.
 9155                // Completions will use it and autoscroll will prioritize it.
 9156                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9157            });
 9158
 9159            if let Some(choices) = &tabstop.choices {
 9160                if let Some(selection) = tabstop.ranges.first() {
 9161                    self.show_snippet_choices(choices, selection.clone(), cx)
 9162                }
 9163            }
 9164
 9165            // If we're already at the last tabstop and it's at the end of the snippet,
 9166            // we're done, we don't need to keep the state around.
 9167            if !tabstop.is_end_tabstop {
 9168                let choices = tabstops
 9169                    .iter()
 9170                    .map(|tabstop| tabstop.choices.clone())
 9171                    .collect();
 9172
 9173                let ranges = tabstops
 9174                    .into_iter()
 9175                    .map(|tabstop| tabstop.ranges)
 9176                    .collect::<Vec<_>>();
 9177
 9178                self.snippet_stack.push(SnippetState {
 9179                    active_index: 0,
 9180                    ranges,
 9181                    choices,
 9182                });
 9183            }
 9184
 9185            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9186            if self.autoclose_regions.is_empty() {
 9187                let snapshot = self.buffer.read(cx).snapshot(cx);
 9188                for selection in &mut self.selections.all::<Point>(cx) {
 9189                    let selection_head = selection.head();
 9190                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9191                        continue;
 9192                    };
 9193
 9194                    let mut bracket_pair = None;
 9195                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9196                    let prev_chars = snapshot
 9197                        .reversed_chars_at(selection_head)
 9198                        .collect::<String>();
 9199                    for (pair, enabled) in scope.brackets() {
 9200                        if enabled
 9201                            && pair.close
 9202                            && prev_chars.starts_with(pair.start.as_str())
 9203                            && next_chars.starts_with(pair.end.as_str())
 9204                        {
 9205                            bracket_pair = Some(pair.clone());
 9206                            break;
 9207                        }
 9208                    }
 9209                    if let Some(pair) = bracket_pair {
 9210                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9211                        let autoclose_enabled =
 9212                            self.use_autoclose && snapshot_settings.use_autoclose;
 9213                        if autoclose_enabled {
 9214                            let start = snapshot.anchor_after(selection_head);
 9215                            let end = snapshot.anchor_after(selection_head);
 9216                            self.autoclose_regions.push(AutocloseRegion {
 9217                                selection_id: selection.id,
 9218                                range: start..end,
 9219                                pair,
 9220                            });
 9221                        }
 9222                    }
 9223                }
 9224            }
 9225        }
 9226        Ok(())
 9227    }
 9228
 9229    pub fn move_to_next_snippet_tabstop(
 9230        &mut self,
 9231        window: &mut Window,
 9232        cx: &mut Context<Self>,
 9233    ) -> bool {
 9234        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9235    }
 9236
 9237    pub fn move_to_prev_snippet_tabstop(
 9238        &mut self,
 9239        window: &mut Window,
 9240        cx: &mut Context<Self>,
 9241    ) -> bool {
 9242        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9243    }
 9244
 9245    pub fn move_to_snippet_tabstop(
 9246        &mut self,
 9247        bias: Bias,
 9248        window: &mut Window,
 9249        cx: &mut Context<Self>,
 9250    ) -> bool {
 9251        if let Some(mut snippet) = self.snippet_stack.pop() {
 9252            match bias {
 9253                Bias::Left => {
 9254                    if snippet.active_index > 0 {
 9255                        snippet.active_index -= 1;
 9256                    } else {
 9257                        self.snippet_stack.push(snippet);
 9258                        return false;
 9259                    }
 9260                }
 9261                Bias::Right => {
 9262                    if snippet.active_index + 1 < snippet.ranges.len() {
 9263                        snippet.active_index += 1;
 9264                    } else {
 9265                        self.snippet_stack.push(snippet);
 9266                        return false;
 9267                    }
 9268                }
 9269            }
 9270            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9271                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9272                    // Reverse order so that the first range is the newest created selection.
 9273                    // Completions will use it and autoscroll will prioritize it.
 9274                    s.select_ranges(current_ranges.iter().rev().cloned())
 9275                });
 9276
 9277                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9278                    if let Some(selection) = current_ranges.first() {
 9279                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9280                    }
 9281                }
 9282
 9283                // If snippet state is not at the last tabstop, push it back on the stack
 9284                if snippet.active_index + 1 < snippet.ranges.len() {
 9285                    self.snippet_stack.push(snippet);
 9286                }
 9287                return true;
 9288            }
 9289        }
 9290
 9291        false
 9292    }
 9293
 9294    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9295        self.transact(window, cx, |this, window, cx| {
 9296            this.select_all(&SelectAll, window, cx);
 9297            this.insert("", window, cx);
 9298        });
 9299    }
 9300
 9301    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9302        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9303        self.transact(window, cx, |this, window, cx| {
 9304            this.select_autoclose_pair(window, cx);
 9305            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9306            if !this.linked_edit_ranges.is_empty() {
 9307                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9308                let snapshot = this.buffer.read(cx).snapshot(cx);
 9309
 9310                for selection in selections.iter() {
 9311                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9312                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9313                    if selection_start.buffer_id != selection_end.buffer_id {
 9314                        continue;
 9315                    }
 9316                    if let Some(ranges) =
 9317                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9318                    {
 9319                        for (buffer, entries) in ranges {
 9320                            linked_ranges.entry(buffer).or_default().extend(entries);
 9321                        }
 9322                    }
 9323                }
 9324            }
 9325
 9326            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9327            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9328            for selection in &mut selections {
 9329                if selection.is_empty() {
 9330                    let old_head = selection.head();
 9331                    let mut new_head =
 9332                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9333                            .to_point(&display_map);
 9334                    if let Some((buffer, line_buffer_range)) = display_map
 9335                        .buffer_snapshot
 9336                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9337                    {
 9338                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9339                        let indent_len = match indent_size.kind {
 9340                            IndentKind::Space => {
 9341                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9342                            }
 9343                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9344                        };
 9345                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9346                            let indent_len = indent_len.get();
 9347                            new_head = cmp::min(
 9348                                new_head,
 9349                                MultiBufferPoint::new(
 9350                                    old_head.row,
 9351                                    ((old_head.column - 1) / indent_len) * indent_len,
 9352                                ),
 9353                            );
 9354                        }
 9355                    }
 9356
 9357                    selection.set_head(new_head, SelectionGoal::None);
 9358                }
 9359            }
 9360
 9361            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9362                s.select(selections)
 9363            });
 9364            this.insert("", window, cx);
 9365            let empty_str: Arc<str> = Arc::from("");
 9366            for (buffer, edits) in linked_ranges {
 9367                let snapshot = buffer.read(cx).snapshot();
 9368                use text::ToPoint as TP;
 9369
 9370                let edits = edits
 9371                    .into_iter()
 9372                    .map(|range| {
 9373                        let end_point = TP::to_point(&range.end, &snapshot);
 9374                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9375
 9376                        if end_point == start_point {
 9377                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9378                                .saturating_sub(1);
 9379                            start_point =
 9380                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9381                        };
 9382
 9383                        (start_point..end_point, empty_str.clone())
 9384                    })
 9385                    .sorted_by_key(|(range, _)| range.start)
 9386                    .collect::<Vec<_>>();
 9387                buffer.update(cx, |this, cx| {
 9388                    this.edit(edits, None, cx);
 9389                })
 9390            }
 9391            this.refresh_inline_completion(true, false, window, cx);
 9392            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9393        });
 9394    }
 9395
 9396    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9397        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9398        self.transact(window, cx, |this, window, cx| {
 9399            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9400                s.move_with(|map, selection| {
 9401                    if selection.is_empty() {
 9402                        let cursor = movement::right(map, selection.head());
 9403                        selection.end = cursor;
 9404                        selection.reversed = true;
 9405                        selection.goal = SelectionGoal::None;
 9406                    }
 9407                })
 9408            });
 9409            this.insert("", window, cx);
 9410            this.refresh_inline_completion(true, false, window, cx);
 9411        });
 9412    }
 9413
 9414    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9415        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9416        if self.move_to_prev_snippet_tabstop(window, cx) {
 9417            return;
 9418        }
 9419        self.outdent(&Outdent, window, cx);
 9420    }
 9421
 9422    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9423        if self.move_to_next_snippet_tabstop(window, cx) {
 9424            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9425            return;
 9426        }
 9427        if self.read_only(cx) {
 9428            return;
 9429        }
 9430        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9431        let mut selections = self.selections.all_adjusted(cx);
 9432        let buffer = self.buffer.read(cx);
 9433        let snapshot = buffer.snapshot(cx);
 9434        let rows_iter = selections.iter().map(|s| s.head().row);
 9435        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9436
 9437        let has_some_cursor_in_whitespace = selections
 9438            .iter()
 9439            .filter(|selection| selection.is_empty())
 9440            .any(|selection| {
 9441                let cursor = selection.head();
 9442                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9443                cursor.column < current_indent.len
 9444            });
 9445
 9446        let mut edits = Vec::new();
 9447        let mut prev_edited_row = 0;
 9448        let mut row_delta = 0;
 9449        for selection in &mut selections {
 9450            if selection.start.row != prev_edited_row {
 9451                row_delta = 0;
 9452            }
 9453            prev_edited_row = selection.end.row;
 9454
 9455            // If the selection is non-empty, then increase the indentation of the selected lines.
 9456            if !selection.is_empty() {
 9457                row_delta =
 9458                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9459                continue;
 9460            }
 9461
 9462            let cursor = selection.head();
 9463            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9464            if let Some(suggested_indent) =
 9465                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9466            {
 9467                // Don't do anything if already at suggested indent
 9468                // and there is any other cursor which is not
 9469                if has_some_cursor_in_whitespace
 9470                    && cursor.column == current_indent.len
 9471                    && current_indent.len == suggested_indent.len
 9472                {
 9473                    continue;
 9474                }
 9475
 9476                // Adjust line and move cursor to suggested indent
 9477                // if cursor is not at suggested indent
 9478                if cursor.column < suggested_indent.len
 9479                    && cursor.column <= current_indent.len
 9480                    && current_indent.len <= suggested_indent.len
 9481                {
 9482                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9483                    selection.end = selection.start;
 9484                    if row_delta == 0 {
 9485                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9486                            cursor.row,
 9487                            current_indent,
 9488                            suggested_indent,
 9489                        ));
 9490                        row_delta = suggested_indent.len - current_indent.len;
 9491                    }
 9492                    continue;
 9493                }
 9494
 9495                // If current indent is more than suggested indent
 9496                // only move cursor to current indent and skip indent
 9497                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9498                    selection.start = Point::new(cursor.row, current_indent.len);
 9499                    selection.end = selection.start;
 9500                    continue;
 9501                }
 9502            }
 9503
 9504            // Otherwise, insert a hard or soft tab.
 9505            let settings = buffer.language_settings_at(cursor, cx);
 9506            let tab_size = if settings.hard_tabs {
 9507                IndentSize::tab()
 9508            } else {
 9509                let tab_size = settings.tab_size.get();
 9510                let indent_remainder = snapshot
 9511                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9512                    .flat_map(str::chars)
 9513                    .fold(row_delta % tab_size, |counter: u32, c| {
 9514                        if c == '\t' {
 9515                            0
 9516                        } else {
 9517                            (counter + 1) % tab_size
 9518                        }
 9519                    });
 9520
 9521                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9522                IndentSize::spaces(chars_to_next_tab_stop)
 9523            };
 9524            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9525            selection.end = selection.start;
 9526            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9527            row_delta += tab_size.len;
 9528        }
 9529
 9530        self.transact(window, cx, |this, window, cx| {
 9531            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9532            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9533                s.select(selections)
 9534            });
 9535            this.refresh_inline_completion(true, false, window, cx);
 9536        });
 9537    }
 9538
 9539    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9540        if self.read_only(cx) {
 9541            return;
 9542        }
 9543        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9544        let mut selections = self.selections.all::<Point>(cx);
 9545        let mut prev_edited_row = 0;
 9546        let mut row_delta = 0;
 9547        let mut edits = Vec::new();
 9548        let buffer = self.buffer.read(cx);
 9549        let snapshot = buffer.snapshot(cx);
 9550        for selection in &mut selections {
 9551            if selection.start.row != prev_edited_row {
 9552                row_delta = 0;
 9553            }
 9554            prev_edited_row = selection.end.row;
 9555
 9556            row_delta =
 9557                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9558        }
 9559
 9560        self.transact(window, cx, |this, window, cx| {
 9561            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9562            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9563                s.select(selections)
 9564            });
 9565        });
 9566    }
 9567
 9568    fn indent_selection(
 9569        buffer: &MultiBuffer,
 9570        snapshot: &MultiBufferSnapshot,
 9571        selection: &mut Selection<Point>,
 9572        edits: &mut Vec<(Range<Point>, String)>,
 9573        delta_for_start_row: u32,
 9574        cx: &App,
 9575    ) -> u32 {
 9576        let settings = buffer.language_settings_at(selection.start, cx);
 9577        let tab_size = settings.tab_size.get();
 9578        let indent_kind = if settings.hard_tabs {
 9579            IndentKind::Tab
 9580        } else {
 9581            IndentKind::Space
 9582        };
 9583        let mut start_row = selection.start.row;
 9584        let mut end_row = selection.end.row + 1;
 9585
 9586        // If a selection ends at the beginning of a line, don't indent
 9587        // that last line.
 9588        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9589            end_row -= 1;
 9590        }
 9591
 9592        // Avoid re-indenting a row that has already been indented by a
 9593        // previous selection, but still update this selection's column
 9594        // to reflect that indentation.
 9595        if delta_for_start_row > 0 {
 9596            start_row += 1;
 9597            selection.start.column += delta_for_start_row;
 9598            if selection.end.row == selection.start.row {
 9599                selection.end.column += delta_for_start_row;
 9600            }
 9601        }
 9602
 9603        let mut delta_for_end_row = 0;
 9604        let has_multiple_rows = start_row + 1 != end_row;
 9605        for row in start_row..end_row {
 9606            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9607            let indent_delta = match (current_indent.kind, indent_kind) {
 9608                (IndentKind::Space, IndentKind::Space) => {
 9609                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9610                    IndentSize::spaces(columns_to_next_tab_stop)
 9611                }
 9612                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9613                (_, IndentKind::Tab) => IndentSize::tab(),
 9614            };
 9615
 9616            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9617                0
 9618            } else {
 9619                selection.start.column
 9620            };
 9621            let row_start = Point::new(row, start);
 9622            edits.push((
 9623                row_start..row_start,
 9624                indent_delta.chars().collect::<String>(),
 9625            ));
 9626
 9627            // Update this selection's endpoints to reflect the indentation.
 9628            if row == selection.start.row {
 9629                selection.start.column += indent_delta.len;
 9630            }
 9631            if row == selection.end.row {
 9632                selection.end.column += indent_delta.len;
 9633                delta_for_end_row = indent_delta.len;
 9634            }
 9635        }
 9636
 9637        if selection.start.row == selection.end.row {
 9638            delta_for_start_row + delta_for_end_row
 9639        } else {
 9640            delta_for_end_row
 9641        }
 9642    }
 9643
 9644    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9645        if self.read_only(cx) {
 9646            return;
 9647        }
 9648        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9649        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9650        let selections = self.selections.all::<Point>(cx);
 9651        let mut deletion_ranges = Vec::new();
 9652        let mut last_outdent = None;
 9653        {
 9654            let buffer = self.buffer.read(cx);
 9655            let snapshot = buffer.snapshot(cx);
 9656            for selection in &selections {
 9657                let settings = buffer.language_settings_at(selection.start, cx);
 9658                let tab_size = settings.tab_size.get();
 9659                let mut rows = selection.spanned_rows(false, &display_map);
 9660
 9661                // Avoid re-outdenting a row that has already been outdented by a
 9662                // previous selection.
 9663                if let Some(last_row) = last_outdent {
 9664                    if last_row == rows.start {
 9665                        rows.start = rows.start.next_row();
 9666                    }
 9667                }
 9668                let has_multiple_rows = rows.len() > 1;
 9669                for row in rows.iter_rows() {
 9670                    let indent_size = snapshot.indent_size_for_line(row);
 9671                    if indent_size.len > 0 {
 9672                        let deletion_len = match indent_size.kind {
 9673                            IndentKind::Space => {
 9674                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9675                                if columns_to_prev_tab_stop == 0 {
 9676                                    tab_size
 9677                                } else {
 9678                                    columns_to_prev_tab_stop
 9679                                }
 9680                            }
 9681                            IndentKind::Tab => 1,
 9682                        };
 9683                        let start = if has_multiple_rows
 9684                            || deletion_len > selection.start.column
 9685                            || indent_size.len < selection.start.column
 9686                        {
 9687                            0
 9688                        } else {
 9689                            selection.start.column - deletion_len
 9690                        };
 9691                        deletion_ranges.push(
 9692                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9693                        );
 9694                        last_outdent = Some(row);
 9695                    }
 9696                }
 9697            }
 9698        }
 9699
 9700        self.transact(window, cx, |this, window, cx| {
 9701            this.buffer.update(cx, |buffer, cx| {
 9702                let empty_str: Arc<str> = Arc::default();
 9703                buffer.edit(
 9704                    deletion_ranges
 9705                        .into_iter()
 9706                        .map(|range| (range, empty_str.clone())),
 9707                    None,
 9708                    cx,
 9709                );
 9710            });
 9711            let selections = this.selections.all::<usize>(cx);
 9712            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9713                s.select(selections)
 9714            });
 9715        });
 9716    }
 9717
 9718    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9719        if self.read_only(cx) {
 9720            return;
 9721        }
 9722        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9723        let selections = self
 9724            .selections
 9725            .all::<usize>(cx)
 9726            .into_iter()
 9727            .map(|s| s.range());
 9728
 9729        self.transact(window, cx, |this, window, cx| {
 9730            this.buffer.update(cx, |buffer, cx| {
 9731                buffer.autoindent_ranges(selections, cx);
 9732            });
 9733            let selections = this.selections.all::<usize>(cx);
 9734            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9735                s.select(selections)
 9736            });
 9737        });
 9738    }
 9739
 9740    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9741        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9743        let selections = self.selections.all::<Point>(cx);
 9744
 9745        let mut new_cursors = Vec::new();
 9746        let mut edit_ranges = Vec::new();
 9747        let mut selections = selections.iter().peekable();
 9748        while let Some(selection) = selections.next() {
 9749            let mut rows = selection.spanned_rows(false, &display_map);
 9750            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9751
 9752            // Accumulate contiguous regions of rows that we want to delete.
 9753            while let Some(next_selection) = selections.peek() {
 9754                let next_rows = next_selection.spanned_rows(false, &display_map);
 9755                if next_rows.start <= rows.end {
 9756                    rows.end = next_rows.end;
 9757                    selections.next().unwrap();
 9758                } else {
 9759                    break;
 9760                }
 9761            }
 9762
 9763            let buffer = &display_map.buffer_snapshot;
 9764            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9765            let edit_end;
 9766            let cursor_buffer_row;
 9767            if buffer.max_point().row >= rows.end.0 {
 9768                // If there's a line after the range, delete the \n from the end of the row range
 9769                // and position the cursor on the next line.
 9770                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9771                cursor_buffer_row = rows.end;
 9772            } else {
 9773                // If there isn't a line after the range, delete the \n from the line before the
 9774                // start of the row range and position the cursor there.
 9775                edit_start = edit_start.saturating_sub(1);
 9776                edit_end = buffer.len();
 9777                cursor_buffer_row = rows.start.previous_row();
 9778            }
 9779
 9780            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9781            *cursor.column_mut() =
 9782                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9783
 9784            new_cursors.push((
 9785                selection.id,
 9786                buffer.anchor_after(cursor.to_point(&display_map)),
 9787            ));
 9788            edit_ranges.push(edit_start..edit_end);
 9789        }
 9790
 9791        self.transact(window, cx, |this, window, cx| {
 9792            let buffer = this.buffer.update(cx, |buffer, cx| {
 9793                let empty_str: Arc<str> = Arc::default();
 9794                buffer.edit(
 9795                    edit_ranges
 9796                        .into_iter()
 9797                        .map(|range| (range, empty_str.clone())),
 9798                    None,
 9799                    cx,
 9800                );
 9801                buffer.snapshot(cx)
 9802            });
 9803            let new_selections = new_cursors
 9804                .into_iter()
 9805                .map(|(id, cursor)| {
 9806                    let cursor = cursor.to_point(&buffer);
 9807                    Selection {
 9808                        id,
 9809                        start: cursor,
 9810                        end: cursor,
 9811                        reversed: false,
 9812                        goal: SelectionGoal::None,
 9813                    }
 9814                })
 9815                .collect();
 9816
 9817            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9818                s.select(new_selections);
 9819            });
 9820        });
 9821    }
 9822
 9823    pub fn join_lines_impl(
 9824        &mut self,
 9825        insert_whitespace: bool,
 9826        window: &mut Window,
 9827        cx: &mut Context<Self>,
 9828    ) {
 9829        if self.read_only(cx) {
 9830            return;
 9831        }
 9832        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9833        for selection in self.selections.all::<Point>(cx) {
 9834            let start = MultiBufferRow(selection.start.row);
 9835            // Treat single line selections as if they include the next line. Otherwise this action
 9836            // would do nothing for single line selections individual cursors.
 9837            let end = if selection.start.row == selection.end.row {
 9838                MultiBufferRow(selection.start.row + 1)
 9839            } else {
 9840                MultiBufferRow(selection.end.row)
 9841            };
 9842
 9843            if let Some(last_row_range) = row_ranges.last_mut() {
 9844                if start <= last_row_range.end {
 9845                    last_row_range.end = end;
 9846                    continue;
 9847                }
 9848            }
 9849            row_ranges.push(start..end);
 9850        }
 9851
 9852        let snapshot = self.buffer.read(cx).snapshot(cx);
 9853        let mut cursor_positions = Vec::new();
 9854        for row_range in &row_ranges {
 9855            let anchor = snapshot.anchor_before(Point::new(
 9856                row_range.end.previous_row().0,
 9857                snapshot.line_len(row_range.end.previous_row()),
 9858            ));
 9859            cursor_positions.push(anchor..anchor);
 9860        }
 9861
 9862        self.transact(window, cx, |this, window, cx| {
 9863            for row_range in row_ranges.into_iter().rev() {
 9864                for row in row_range.iter_rows().rev() {
 9865                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9866                    let next_line_row = row.next_row();
 9867                    let indent = snapshot.indent_size_for_line(next_line_row);
 9868                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9869
 9870                    let replace =
 9871                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9872                            " "
 9873                        } else {
 9874                            ""
 9875                        };
 9876
 9877                    this.buffer.update(cx, |buffer, cx| {
 9878                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9879                    });
 9880                }
 9881            }
 9882
 9883            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9884                s.select_anchor_ranges(cursor_positions)
 9885            });
 9886        });
 9887    }
 9888
 9889    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9890        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9891        self.join_lines_impl(true, window, cx);
 9892    }
 9893
 9894    pub fn sort_lines_case_sensitive(
 9895        &mut self,
 9896        _: &SortLinesCaseSensitive,
 9897        window: &mut Window,
 9898        cx: &mut Context<Self>,
 9899    ) {
 9900        self.manipulate_lines(window, cx, |lines| lines.sort())
 9901    }
 9902
 9903    pub fn sort_lines_case_insensitive(
 9904        &mut self,
 9905        _: &SortLinesCaseInsensitive,
 9906        window: &mut Window,
 9907        cx: &mut Context<Self>,
 9908    ) {
 9909        self.manipulate_lines(window, cx, |lines| {
 9910            lines.sort_by_key(|line| line.to_lowercase())
 9911        })
 9912    }
 9913
 9914    pub fn unique_lines_case_insensitive(
 9915        &mut self,
 9916        _: &UniqueLinesCaseInsensitive,
 9917        window: &mut Window,
 9918        cx: &mut Context<Self>,
 9919    ) {
 9920        self.manipulate_lines(window, cx, |lines| {
 9921            let mut seen = HashSet::default();
 9922            lines.retain(|line| seen.insert(line.to_lowercase()));
 9923        })
 9924    }
 9925
 9926    pub fn unique_lines_case_sensitive(
 9927        &mut self,
 9928        _: &UniqueLinesCaseSensitive,
 9929        window: &mut Window,
 9930        cx: &mut Context<Self>,
 9931    ) {
 9932        self.manipulate_lines(window, cx, |lines| {
 9933            let mut seen = HashSet::default();
 9934            lines.retain(|line| seen.insert(*line));
 9935        })
 9936    }
 9937
 9938    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9939        let Some(project) = self.project.clone() else {
 9940            return;
 9941        };
 9942        self.reload(project, window, cx)
 9943            .detach_and_notify_err(window, cx);
 9944    }
 9945
 9946    pub fn restore_file(
 9947        &mut self,
 9948        _: &::git::RestoreFile,
 9949        window: &mut Window,
 9950        cx: &mut Context<Self>,
 9951    ) {
 9952        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9953        let mut buffer_ids = HashSet::default();
 9954        let snapshot = self.buffer().read(cx).snapshot(cx);
 9955        for selection in self.selections.all::<usize>(cx) {
 9956            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9957        }
 9958
 9959        let buffer = self.buffer().read(cx);
 9960        let ranges = buffer_ids
 9961            .into_iter()
 9962            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9963            .collect::<Vec<_>>();
 9964
 9965        self.restore_hunks_in_ranges(ranges, window, cx);
 9966    }
 9967
 9968    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9969        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9970        let selections = self
 9971            .selections
 9972            .all(cx)
 9973            .into_iter()
 9974            .map(|s| s.range())
 9975            .collect();
 9976        self.restore_hunks_in_ranges(selections, window, cx);
 9977    }
 9978
 9979    pub fn restore_hunks_in_ranges(
 9980        &mut self,
 9981        ranges: Vec<Range<Point>>,
 9982        window: &mut Window,
 9983        cx: &mut Context<Editor>,
 9984    ) {
 9985        let mut revert_changes = HashMap::default();
 9986        let chunk_by = self
 9987            .snapshot(window, cx)
 9988            .hunks_for_ranges(ranges)
 9989            .into_iter()
 9990            .chunk_by(|hunk| hunk.buffer_id);
 9991        for (buffer_id, hunks) in &chunk_by {
 9992            let hunks = hunks.collect::<Vec<_>>();
 9993            for hunk in &hunks {
 9994                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9995            }
 9996            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9997        }
 9998        drop(chunk_by);
 9999        if !revert_changes.is_empty() {
10000            self.transact(window, cx, |editor, window, cx| {
10001                editor.restore(revert_changes, window, cx);
10002            });
10003        }
10004    }
10005
10006    pub fn open_active_item_in_terminal(
10007        &mut self,
10008        _: &OpenInTerminal,
10009        window: &mut Window,
10010        cx: &mut Context<Self>,
10011    ) {
10012        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10013            let project_path = buffer.read(cx).project_path(cx)?;
10014            let project = self.project.as_ref()?.read(cx);
10015            let entry = project.entry_for_path(&project_path, cx)?;
10016            let parent = match &entry.canonical_path {
10017                Some(canonical_path) => canonical_path.to_path_buf(),
10018                None => project.absolute_path(&project_path, cx)?,
10019            }
10020            .parent()?
10021            .to_path_buf();
10022            Some(parent)
10023        }) {
10024            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10025        }
10026    }
10027
10028    fn set_breakpoint_context_menu(
10029        &mut self,
10030        display_row: DisplayRow,
10031        position: Option<Anchor>,
10032        clicked_point: gpui::Point<Pixels>,
10033        window: &mut Window,
10034        cx: &mut Context<Self>,
10035    ) {
10036        if !cx.has_flag::<DebuggerFeatureFlag>() {
10037            return;
10038        }
10039        let source = self
10040            .buffer
10041            .read(cx)
10042            .snapshot(cx)
10043            .anchor_before(Point::new(display_row.0, 0u32));
10044
10045        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10046
10047        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10048            self,
10049            source,
10050            clicked_point,
10051            context_menu,
10052            window,
10053            cx,
10054        );
10055    }
10056
10057    fn add_edit_breakpoint_block(
10058        &mut self,
10059        anchor: Anchor,
10060        breakpoint: &Breakpoint,
10061        edit_action: BreakpointPromptEditAction,
10062        window: &mut Window,
10063        cx: &mut Context<Self>,
10064    ) {
10065        let weak_editor = cx.weak_entity();
10066        let bp_prompt = cx.new(|cx| {
10067            BreakpointPromptEditor::new(
10068                weak_editor,
10069                anchor,
10070                breakpoint.clone(),
10071                edit_action,
10072                window,
10073                cx,
10074            )
10075        });
10076
10077        let height = bp_prompt.update(cx, |this, cx| {
10078            this.prompt
10079                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10080        });
10081        let cloned_prompt = bp_prompt.clone();
10082        let blocks = vec![BlockProperties {
10083            style: BlockStyle::Sticky,
10084            placement: BlockPlacement::Above(anchor),
10085            height: Some(height),
10086            render: Arc::new(move |cx| {
10087                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10088                cloned_prompt.clone().into_any_element()
10089            }),
10090            priority: 0,
10091            render_in_minimap: true,
10092        }];
10093
10094        let focus_handle = bp_prompt.focus_handle(cx);
10095        window.focus(&focus_handle);
10096
10097        let block_ids = self.insert_blocks(blocks, None, cx);
10098        bp_prompt.update(cx, |prompt, _| {
10099            prompt.add_block_ids(block_ids);
10100        });
10101    }
10102
10103    pub(crate) fn breakpoint_at_row(
10104        &self,
10105        row: u32,
10106        window: &mut Window,
10107        cx: &mut Context<Self>,
10108    ) -> Option<(Anchor, Breakpoint)> {
10109        let snapshot = self.snapshot(window, cx);
10110        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10111
10112        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10113    }
10114
10115    pub(crate) fn breakpoint_at_anchor(
10116        &self,
10117        breakpoint_position: Anchor,
10118        snapshot: &EditorSnapshot,
10119        cx: &mut Context<Self>,
10120    ) -> Option<(Anchor, Breakpoint)> {
10121        let project = self.project.clone()?;
10122
10123        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10124            snapshot
10125                .buffer_snapshot
10126                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10127        })?;
10128
10129        let enclosing_excerpt = breakpoint_position.excerpt_id;
10130        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10131        let buffer_snapshot = buffer.read(cx).snapshot();
10132
10133        let row = buffer_snapshot
10134            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10135            .row;
10136
10137        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10138        let anchor_end = snapshot
10139            .buffer_snapshot
10140            .anchor_after(Point::new(row, line_len));
10141
10142        let bp = self
10143            .breakpoint_store
10144            .as_ref()?
10145            .read_with(cx, |breakpoint_store, cx| {
10146                breakpoint_store
10147                    .breakpoints(
10148                        &buffer,
10149                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10150                        &buffer_snapshot,
10151                        cx,
10152                    )
10153                    .next()
10154                    .and_then(|(bp, _)| {
10155                        let breakpoint_row = buffer_snapshot
10156                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10157                            .row;
10158
10159                        if breakpoint_row == row {
10160                            snapshot
10161                                .buffer_snapshot
10162                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10163                                .map(|position| (position, bp.bp.clone()))
10164                        } else {
10165                            None
10166                        }
10167                    })
10168            });
10169        bp
10170    }
10171
10172    pub fn edit_log_breakpoint(
10173        &mut self,
10174        _: &EditLogBreakpoint,
10175        window: &mut Window,
10176        cx: &mut Context<Self>,
10177    ) {
10178        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10179            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10180                message: None,
10181                state: BreakpointState::Enabled,
10182                condition: None,
10183                hit_condition: None,
10184            });
10185
10186            self.add_edit_breakpoint_block(
10187                anchor,
10188                &breakpoint,
10189                BreakpointPromptEditAction::Log,
10190                window,
10191                cx,
10192            );
10193        }
10194    }
10195
10196    fn breakpoints_at_cursors(
10197        &self,
10198        window: &mut Window,
10199        cx: &mut Context<Self>,
10200    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10201        let snapshot = self.snapshot(window, cx);
10202        let cursors = self
10203            .selections
10204            .disjoint_anchors()
10205            .into_iter()
10206            .map(|selection| {
10207                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10208
10209                let breakpoint_position = self
10210                    .breakpoint_at_row(cursor_position.row, window, cx)
10211                    .map(|bp| bp.0)
10212                    .unwrap_or_else(|| {
10213                        snapshot
10214                            .display_snapshot
10215                            .buffer_snapshot
10216                            .anchor_after(Point::new(cursor_position.row, 0))
10217                    });
10218
10219                let breakpoint = self
10220                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10221                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10222
10223                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10224            })
10225            // 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.
10226            .collect::<HashMap<Anchor, _>>();
10227
10228        cursors.into_iter().collect()
10229    }
10230
10231    pub fn enable_breakpoint(
10232        &mut self,
10233        _: &crate::actions::EnableBreakpoint,
10234        window: &mut Window,
10235        cx: &mut Context<Self>,
10236    ) {
10237        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10238            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10239                continue;
10240            };
10241            self.edit_breakpoint_at_anchor(
10242                anchor,
10243                breakpoint,
10244                BreakpointEditAction::InvertState,
10245                cx,
10246            );
10247        }
10248    }
10249
10250    pub fn disable_breakpoint(
10251        &mut self,
10252        _: &crate::actions::DisableBreakpoint,
10253        window: &mut Window,
10254        cx: &mut Context<Self>,
10255    ) {
10256        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10257            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10258                continue;
10259            };
10260            self.edit_breakpoint_at_anchor(
10261                anchor,
10262                breakpoint,
10263                BreakpointEditAction::InvertState,
10264                cx,
10265            );
10266        }
10267    }
10268
10269    pub fn toggle_breakpoint(
10270        &mut self,
10271        _: &crate::actions::ToggleBreakpoint,
10272        window: &mut Window,
10273        cx: &mut Context<Self>,
10274    ) {
10275        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10276            if let Some(breakpoint) = breakpoint {
10277                self.edit_breakpoint_at_anchor(
10278                    anchor,
10279                    breakpoint,
10280                    BreakpointEditAction::Toggle,
10281                    cx,
10282                );
10283            } else {
10284                self.edit_breakpoint_at_anchor(
10285                    anchor,
10286                    Breakpoint::new_standard(),
10287                    BreakpointEditAction::Toggle,
10288                    cx,
10289                );
10290            }
10291        }
10292    }
10293
10294    pub fn edit_breakpoint_at_anchor(
10295        &mut self,
10296        breakpoint_position: Anchor,
10297        breakpoint: Breakpoint,
10298        edit_action: BreakpointEditAction,
10299        cx: &mut Context<Self>,
10300    ) {
10301        let Some(breakpoint_store) = &self.breakpoint_store else {
10302            return;
10303        };
10304
10305        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10306            if breakpoint_position == Anchor::min() {
10307                self.buffer()
10308                    .read(cx)
10309                    .excerpt_buffer_ids()
10310                    .into_iter()
10311                    .next()
10312            } else {
10313                None
10314            }
10315        }) else {
10316            return;
10317        };
10318
10319        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10320            return;
10321        };
10322
10323        breakpoint_store.update(cx, |breakpoint_store, cx| {
10324            breakpoint_store.toggle_breakpoint(
10325                buffer,
10326                BreakpointWithPosition {
10327                    position: breakpoint_position.text_anchor,
10328                    bp: breakpoint,
10329                },
10330                edit_action,
10331                cx,
10332            );
10333        });
10334
10335        cx.notify();
10336    }
10337
10338    #[cfg(any(test, feature = "test-support"))]
10339    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10340        self.breakpoint_store.clone()
10341    }
10342
10343    pub fn prepare_restore_change(
10344        &self,
10345        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10346        hunk: &MultiBufferDiffHunk,
10347        cx: &mut App,
10348    ) -> Option<()> {
10349        if hunk.is_created_file() {
10350            return None;
10351        }
10352        let buffer = self.buffer.read(cx);
10353        let diff = buffer.diff_for(hunk.buffer_id)?;
10354        let buffer = buffer.buffer(hunk.buffer_id)?;
10355        let buffer = buffer.read(cx);
10356        let original_text = diff
10357            .read(cx)
10358            .base_text()
10359            .as_rope()
10360            .slice(hunk.diff_base_byte_range.clone());
10361        let buffer_snapshot = buffer.snapshot();
10362        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10363        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10364            probe
10365                .0
10366                .start
10367                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10368                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10369        }) {
10370            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10371            Some(())
10372        } else {
10373            None
10374        }
10375    }
10376
10377    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10378        self.manipulate_lines(window, cx, |lines| lines.reverse())
10379    }
10380
10381    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10382        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10383    }
10384
10385    fn manipulate_lines<Fn>(
10386        &mut self,
10387        window: &mut Window,
10388        cx: &mut Context<Self>,
10389        mut callback: Fn,
10390    ) where
10391        Fn: FnMut(&mut Vec<&str>),
10392    {
10393        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10394
10395        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10396        let buffer = self.buffer.read(cx).snapshot(cx);
10397
10398        let mut edits = Vec::new();
10399
10400        let selections = self.selections.all::<Point>(cx);
10401        let mut selections = selections.iter().peekable();
10402        let mut contiguous_row_selections = Vec::new();
10403        let mut new_selections = Vec::new();
10404        let mut added_lines = 0;
10405        let mut removed_lines = 0;
10406
10407        while let Some(selection) = selections.next() {
10408            let (start_row, end_row) = consume_contiguous_rows(
10409                &mut contiguous_row_selections,
10410                selection,
10411                &display_map,
10412                &mut selections,
10413            );
10414
10415            let start_point = Point::new(start_row.0, 0);
10416            let end_point = Point::new(
10417                end_row.previous_row().0,
10418                buffer.line_len(end_row.previous_row()),
10419            );
10420            let text = buffer
10421                .text_for_range(start_point..end_point)
10422                .collect::<String>();
10423
10424            let mut lines = text.split('\n').collect_vec();
10425
10426            let lines_before = lines.len();
10427            callback(&mut lines);
10428            let lines_after = lines.len();
10429
10430            edits.push((start_point..end_point, lines.join("\n")));
10431
10432            // Selections must change based on added and removed line count
10433            let start_row =
10434                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10435            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10436            new_selections.push(Selection {
10437                id: selection.id,
10438                start: start_row,
10439                end: end_row,
10440                goal: SelectionGoal::None,
10441                reversed: selection.reversed,
10442            });
10443
10444            if lines_after > lines_before {
10445                added_lines += lines_after - lines_before;
10446            } else if lines_before > lines_after {
10447                removed_lines += lines_before - lines_after;
10448            }
10449        }
10450
10451        self.transact(window, cx, |this, window, cx| {
10452            let buffer = this.buffer.update(cx, |buffer, cx| {
10453                buffer.edit(edits, None, cx);
10454                buffer.snapshot(cx)
10455            });
10456
10457            // Recalculate offsets on newly edited buffer
10458            let new_selections = new_selections
10459                .iter()
10460                .map(|s| {
10461                    let start_point = Point::new(s.start.0, 0);
10462                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10463                    Selection {
10464                        id: s.id,
10465                        start: buffer.point_to_offset(start_point),
10466                        end: buffer.point_to_offset(end_point),
10467                        goal: s.goal,
10468                        reversed: s.reversed,
10469                    }
10470                })
10471                .collect();
10472
10473            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10474                s.select(new_selections);
10475            });
10476
10477            this.request_autoscroll(Autoscroll::fit(), cx);
10478        });
10479    }
10480
10481    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10482        self.manipulate_text(window, cx, |text| {
10483            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10484            if has_upper_case_characters {
10485                text.to_lowercase()
10486            } else {
10487                text.to_uppercase()
10488            }
10489        })
10490    }
10491
10492    pub fn convert_to_upper_case(
10493        &mut self,
10494        _: &ConvertToUpperCase,
10495        window: &mut Window,
10496        cx: &mut Context<Self>,
10497    ) {
10498        self.manipulate_text(window, cx, |text| text.to_uppercase())
10499    }
10500
10501    pub fn convert_to_lower_case(
10502        &mut self,
10503        _: &ConvertToLowerCase,
10504        window: &mut Window,
10505        cx: &mut Context<Self>,
10506    ) {
10507        self.manipulate_text(window, cx, |text| text.to_lowercase())
10508    }
10509
10510    pub fn convert_to_title_case(
10511        &mut self,
10512        _: &ConvertToTitleCase,
10513        window: &mut Window,
10514        cx: &mut Context<Self>,
10515    ) {
10516        self.manipulate_text(window, cx, |text| {
10517            text.split('\n')
10518                .map(|line| line.to_case(Case::Title))
10519                .join("\n")
10520        })
10521    }
10522
10523    pub fn convert_to_snake_case(
10524        &mut self,
10525        _: &ConvertToSnakeCase,
10526        window: &mut Window,
10527        cx: &mut Context<Self>,
10528    ) {
10529        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10530    }
10531
10532    pub fn convert_to_kebab_case(
10533        &mut self,
10534        _: &ConvertToKebabCase,
10535        window: &mut Window,
10536        cx: &mut Context<Self>,
10537    ) {
10538        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10539    }
10540
10541    pub fn convert_to_upper_camel_case(
10542        &mut self,
10543        _: &ConvertToUpperCamelCase,
10544        window: &mut Window,
10545        cx: &mut Context<Self>,
10546    ) {
10547        self.manipulate_text(window, cx, |text| {
10548            text.split('\n')
10549                .map(|line| line.to_case(Case::UpperCamel))
10550                .join("\n")
10551        })
10552    }
10553
10554    pub fn convert_to_lower_camel_case(
10555        &mut self,
10556        _: &ConvertToLowerCamelCase,
10557        window: &mut Window,
10558        cx: &mut Context<Self>,
10559    ) {
10560        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10561    }
10562
10563    pub fn convert_to_opposite_case(
10564        &mut self,
10565        _: &ConvertToOppositeCase,
10566        window: &mut Window,
10567        cx: &mut Context<Self>,
10568    ) {
10569        self.manipulate_text(window, cx, |text| {
10570            text.chars()
10571                .fold(String::with_capacity(text.len()), |mut t, c| {
10572                    if c.is_uppercase() {
10573                        t.extend(c.to_lowercase());
10574                    } else {
10575                        t.extend(c.to_uppercase());
10576                    }
10577                    t
10578                })
10579        })
10580    }
10581
10582    pub fn convert_to_rot13(
10583        &mut self,
10584        _: &ConvertToRot13,
10585        window: &mut Window,
10586        cx: &mut Context<Self>,
10587    ) {
10588        self.manipulate_text(window, cx, |text| {
10589            text.chars()
10590                .map(|c| match c {
10591                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10592                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10593                    _ => c,
10594                })
10595                .collect()
10596        })
10597    }
10598
10599    pub fn convert_to_rot47(
10600        &mut self,
10601        _: &ConvertToRot47,
10602        window: &mut Window,
10603        cx: &mut Context<Self>,
10604    ) {
10605        self.manipulate_text(window, cx, |text| {
10606            text.chars()
10607                .map(|c| {
10608                    let code_point = c as u32;
10609                    if code_point >= 33 && code_point <= 126 {
10610                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10611                    }
10612                    c
10613                })
10614                .collect()
10615        })
10616    }
10617
10618    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10619    where
10620        Fn: FnMut(&str) -> String,
10621    {
10622        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10623        let buffer = self.buffer.read(cx).snapshot(cx);
10624
10625        let mut new_selections = Vec::new();
10626        let mut edits = Vec::new();
10627        let mut selection_adjustment = 0i32;
10628
10629        for selection in self.selections.all::<usize>(cx) {
10630            let selection_is_empty = selection.is_empty();
10631
10632            let (start, end) = if selection_is_empty {
10633                let word_range = movement::surrounding_word(
10634                    &display_map,
10635                    selection.start.to_display_point(&display_map),
10636                );
10637                let start = word_range.start.to_offset(&display_map, Bias::Left);
10638                let end = word_range.end.to_offset(&display_map, Bias::Left);
10639                (start, end)
10640            } else {
10641                (selection.start, selection.end)
10642            };
10643
10644            let text = buffer.text_for_range(start..end).collect::<String>();
10645            let old_length = text.len() as i32;
10646            let text = callback(&text);
10647
10648            new_selections.push(Selection {
10649                start: (start as i32 - selection_adjustment) as usize,
10650                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10651                goal: SelectionGoal::None,
10652                ..selection
10653            });
10654
10655            selection_adjustment += old_length - text.len() as i32;
10656
10657            edits.push((start..end, text));
10658        }
10659
10660        self.transact(window, cx, |this, window, cx| {
10661            this.buffer.update(cx, |buffer, cx| {
10662                buffer.edit(edits, None, cx);
10663            });
10664
10665            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10666                s.select(new_selections);
10667            });
10668
10669            this.request_autoscroll(Autoscroll::fit(), cx);
10670        });
10671    }
10672
10673    pub fn move_selection_on_drop(
10674        &mut self,
10675        selection: &Selection<Anchor>,
10676        target: DisplayPoint,
10677        is_cut: bool,
10678        window: &mut Window,
10679        cx: &mut Context<Self>,
10680    ) {
10681        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10682        let buffer = &display_map.buffer_snapshot;
10683        let mut edits = Vec::new();
10684        let insert_point = display_map
10685            .clip_point(target, Bias::Left)
10686            .to_point(&display_map);
10687        let text = buffer
10688            .text_for_range(selection.start..selection.end)
10689            .collect::<String>();
10690        if is_cut {
10691            edits.push(((selection.start..selection.end), String::new()));
10692        }
10693        let insert_anchor = buffer.anchor_before(insert_point);
10694        edits.push(((insert_anchor..insert_anchor), text));
10695        let last_edit_start = insert_anchor.bias_left(buffer);
10696        let last_edit_end = insert_anchor.bias_right(buffer);
10697        self.transact(window, cx, |this, window, cx| {
10698            this.buffer.update(cx, |buffer, cx| {
10699                buffer.edit(edits, None, cx);
10700            });
10701            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10702                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10703            });
10704        });
10705    }
10706
10707    pub fn clear_selection_drag_state(&mut self) {
10708        self.selection_drag_state = SelectionDragState::None;
10709    }
10710
10711    pub fn duplicate(
10712        &mut self,
10713        upwards: bool,
10714        whole_lines: bool,
10715        window: &mut Window,
10716        cx: &mut Context<Self>,
10717    ) {
10718        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10719
10720        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10721        let buffer = &display_map.buffer_snapshot;
10722        let selections = self.selections.all::<Point>(cx);
10723
10724        let mut edits = Vec::new();
10725        let mut selections_iter = selections.iter().peekable();
10726        while let Some(selection) = selections_iter.next() {
10727            let mut rows = selection.spanned_rows(false, &display_map);
10728            // duplicate line-wise
10729            if whole_lines || selection.start == selection.end {
10730                // Avoid duplicating the same lines twice.
10731                while let Some(next_selection) = selections_iter.peek() {
10732                    let next_rows = next_selection.spanned_rows(false, &display_map);
10733                    if next_rows.start < rows.end {
10734                        rows.end = next_rows.end;
10735                        selections_iter.next().unwrap();
10736                    } else {
10737                        break;
10738                    }
10739                }
10740
10741                // Copy the text from the selected row region and splice it either at the start
10742                // or end of the region.
10743                let start = Point::new(rows.start.0, 0);
10744                let end = Point::new(
10745                    rows.end.previous_row().0,
10746                    buffer.line_len(rows.end.previous_row()),
10747                );
10748                let text = buffer
10749                    .text_for_range(start..end)
10750                    .chain(Some("\n"))
10751                    .collect::<String>();
10752                let insert_location = if upwards {
10753                    Point::new(rows.end.0, 0)
10754                } else {
10755                    start
10756                };
10757                edits.push((insert_location..insert_location, text));
10758            } else {
10759                // duplicate character-wise
10760                let start = selection.start;
10761                let end = selection.end;
10762                let text = buffer.text_for_range(start..end).collect::<String>();
10763                edits.push((selection.end..selection.end, text));
10764            }
10765        }
10766
10767        self.transact(window, cx, |this, _, cx| {
10768            this.buffer.update(cx, |buffer, cx| {
10769                buffer.edit(edits, None, cx);
10770            });
10771
10772            this.request_autoscroll(Autoscroll::fit(), cx);
10773        });
10774    }
10775
10776    pub fn duplicate_line_up(
10777        &mut self,
10778        _: &DuplicateLineUp,
10779        window: &mut Window,
10780        cx: &mut Context<Self>,
10781    ) {
10782        self.duplicate(true, true, window, cx);
10783    }
10784
10785    pub fn duplicate_line_down(
10786        &mut self,
10787        _: &DuplicateLineDown,
10788        window: &mut Window,
10789        cx: &mut Context<Self>,
10790    ) {
10791        self.duplicate(false, true, window, cx);
10792    }
10793
10794    pub fn duplicate_selection(
10795        &mut self,
10796        _: &DuplicateSelection,
10797        window: &mut Window,
10798        cx: &mut Context<Self>,
10799    ) {
10800        self.duplicate(false, false, window, cx);
10801    }
10802
10803    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10804        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10805
10806        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10807        let buffer = self.buffer.read(cx).snapshot(cx);
10808
10809        let mut edits = Vec::new();
10810        let mut unfold_ranges = Vec::new();
10811        let mut refold_creases = Vec::new();
10812
10813        let selections = self.selections.all::<Point>(cx);
10814        let mut selections = selections.iter().peekable();
10815        let mut contiguous_row_selections = Vec::new();
10816        let mut new_selections = Vec::new();
10817
10818        while let Some(selection) = selections.next() {
10819            // Find all the selections that span a contiguous row range
10820            let (start_row, end_row) = consume_contiguous_rows(
10821                &mut contiguous_row_selections,
10822                selection,
10823                &display_map,
10824                &mut selections,
10825            );
10826
10827            // Move the text spanned by the row range to be before the line preceding the row range
10828            if start_row.0 > 0 {
10829                let range_to_move = Point::new(
10830                    start_row.previous_row().0,
10831                    buffer.line_len(start_row.previous_row()),
10832                )
10833                    ..Point::new(
10834                        end_row.previous_row().0,
10835                        buffer.line_len(end_row.previous_row()),
10836                    );
10837                let insertion_point = display_map
10838                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10839                    .0;
10840
10841                // Don't move lines across excerpts
10842                if buffer
10843                    .excerpt_containing(insertion_point..range_to_move.end)
10844                    .is_some()
10845                {
10846                    let text = buffer
10847                        .text_for_range(range_to_move.clone())
10848                        .flat_map(|s| s.chars())
10849                        .skip(1)
10850                        .chain(['\n'])
10851                        .collect::<String>();
10852
10853                    edits.push((
10854                        buffer.anchor_after(range_to_move.start)
10855                            ..buffer.anchor_before(range_to_move.end),
10856                        String::new(),
10857                    ));
10858                    let insertion_anchor = buffer.anchor_after(insertion_point);
10859                    edits.push((insertion_anchor..insertion_anchor, text));
10860
10861                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10862
10863                    // Move selections up
10864                    new_selections.extend(contiguous_row_selections.drain(..).map(
10865                        |mut selection| {
10866                            selection.start.row -= row_delta;
10867                            selection.end.row -= row_delta;
10868                            selection
10869                        },
10870                    ));
10871
10872                    // Move folds up
10873                    unfold_ranges.push(range_to_move.clone());
10874                    for fold in display_map.folds_in_range(
10875                        buffer.anchor_before(range_to_move.start)
10876                            ..buffer.anchor_after(range_to_move.end),
10877                    ) {
10878                        let mut start = fold.range.start.to_point(&buffer);
10879                        let mut end = fold.range.end.to_point(&buffer);
10880                        start.row -= row_delta;
10881                        end.row -= row_delta;
10882                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10883                    }
10884                }
10885            }
10886
10887            // If we didn't move line(s), preserve the existing selections
10888            new_selections.append(&mut contiguous_row_selections);
10889        }
10890
10891        self.transact(window, cx, |this, window, cx| {
10892            this.unfold_ranges(&unfold_ranges, true, true, cx);
10893            this.buffer.update(cx, |buffer, cx| {
10894                for (range, text) in edits {
10895                    buffer.edit([(range, text)], None, cx);
10896                }
10897            });
10898            this.fold_creases(refold_creases, true, window, cx);
10899            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10900                s.select(new_selections);
10901            })
10902        });
10903    }
10904
10905    pub fn move_line_down(
10906        &mut self,
10907        _: &MoveLineDown,
10908        window: &mut Window,
10909        cx: &mut Context<Self>,
10910    ) {
10911        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10912
10913        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10914        let buffer = self.buffer.read(cx).snapshot(cx);
10915
10916        let mut edits = Vec::new();
10917        let mut unfold_ranges = Vec::new();
10918        let mut refold_creases = Vec::new();
10919
10920        let selections = self.selections.all::<Point>(cx);
10921        let mut selections = selections.iter().peekable();
10922        let mut contiguous_row_selections = Vec::new();
10923        let mut new_selections = Vec::new();
10924
10925        while let Some(selection) = selections.next() {
10926            // Find all the selections that span a contiguous row range
10927            let (start_row, end_row) = consume_contiguous_rows(
10928                &mut contiguous_row_selections,
10929                selection,
10930                &display_map,
10931                &mut selections,
10932            );
10933
10934            // Move the text spanned by the row range to be after the last line of the row range
10935            if end_row.0 <= buffer.max_point().row {
10936                let range_to_move =
10937                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10938                let insertion_point = display_map
10939                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10940                    .0;
10941
10942                // Don't move lines across excerpt boundaries
10943                if buffer
10944                    .excerpt_containing(range_to_move.start..insertion_point)
10945                    .is_some()
10946                {
10947                    let mut text = String::from("\n");
10948                    text.extend(buffer.text_for_range(range_to_move.clone()));
10949                    text.pop(); // Drop trailing newline
10950                    edits.push((
10951                        buffer.anchor_after(range_to_move.start)
10952                            ..buffer.anchor_before(range_to_move.end),
10953                        String::new(),
10954                    ));
10955                    let insertion_anchor = buffer.anchor_after(insertion_point);
10956                    edits.push((insertion_anchor..insertion_anchor, text));
10957
10958                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10959
10960                    // Move selections down
10961                    new_selections.extend(contiguous_row_selections.drain(..).map(
10962                        |mut selection| {
10963                            selection.start.row += row_delta;
10964                            selection.end.row += row_delta;
10965                            selection
10966                        },
10967                    ));
10968
10969                    // Move folds down
10970                    unfold_ranges.push(range_to_move.clone());
10971                    for fold in display_map.folds_in_range(
10972                        buffer.anchor_before(range_to_move.start)
10973                            ..buffer.anchor_after(range_to_move.end),
10974                    ) {
10975                        let mut start = fold.range.start.to_point(&buffer);
10976                        let mut end = fold.range.end.to_point(&buffer);
10977                        start.row += row_delta;
10978                        end.row += row_delta;
10979                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10980                    }
10981                }
10982            }
10983
10984            // If we didn't move line(s), preserve the existing selections
10985            new_selections.append(&mut contiguous_row_selections);
10986        }
10987
10988        self.transact(window, cx, |this, window, cx| {
10989            this.unfold_ranges(&unfold_ranges, true, true, cx);
10990            this.buffer.update(cx, |buffer, cx| {
10991                for (range, text) in edits {
10992                    buffer.edit([(range, text)], None, cx);
10993                }
10994            });
10995            this.fold_creases(refold_creases, true, window, cx);
10996            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10997                s.select(new_selections)
10998            });
10999        });
11000    }
11001
11002    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11003        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11004        let text_layout_details = &self.text_layout_details(window);
11005        self.transact(window, cx, |this, window, cx| {
11006            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11007                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11008                s.move_with(|display_map, selection| {
11009                    if !selection.is_empty() {
11010                        return;
11011                    }
11012
11013                    let mut head = selection.head();
11014                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11015                    if head.column() == display_map.line_len(head.row()) {
11016                        transpose_offset = display_map
11017                            .buffer_snapshot
11018                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11019                    }
11020
11021                    if transpose_offset == 0 {
11022                        return;
11023                    }
11024
11025                    *head.column_mut() += 1;
11026                    head = display_map.clip_point(head, Bias::Right);
11027                    let goal = SelectionGoal::HorizontalPosition(
11028                        display_map
11029                            .x_for_display_point(head, text_layout_details)
11030                            .into(),
11031                    );
11032                    selection.collapse_to(head, goal);
11033
11034                    let transpose_start = display_map
11035                        .buffer_snapshot
11036                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11037                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11038                        let transpose_end = display_map
11039                            .buffer_snapshot
11040                            .clip_offset(transpose_offset + 1, Bias::Right);
11041                        if let Some(ch) =
11042                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11043                        {
11044                            edits.push((transpose_start..transpose_offset, String::new()));
11045                            edits.push((transpose_end..transpose_end, ch.to_string()));
11046                        }
11047                    }
11048                });
11049                edits
11050            });
11051            this.buffer
11052                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11053            let selections = this.selections.all::<usize>(cx);
11054            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11055                s.select(selections);
11056            });
11057        });
11058    }
11059
11060    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11061        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11062        self.rewrap_impl(RewrapOptions::default(), cx)
11063    }
11064
11065    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11066        let buffer = self.buffer.read(cx).snapshot(cx);
11067        let selections = self.selections.all::<Point>(cx);
11068
11069        // Shrink and split selections to respect paragraph boundaries.
11070        let ranges = selections.into_iter().flat_map(|selection| {
11071            let language_settings = buffer.language_settings_at(selection.head(), cx);
11072            let language_scope = buffer.language_scope_at(selection.head());
11073
11074            let Some(start_row) = (selection.start.row..=selection.end.row)
11075                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11076            else {
11077                return vec![];
11078            };
11079            let Some(end_row) = (selection.start.row..=selection.end.row)
11080                .rev()
11081                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11082            else {
11083                return vec![];
11084            };
11085
11086            let mut row = start_row;
11087            let mut ranges = Vec::new();
11088            while let Some(blank_row) =
11089                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11090            {
11091                let next_paragraph_start = (blank_row + 1..=end_row)
11092                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11093                    .unwrap();
11094                ranges.push((
11095                    language_settings.clone(),
11096                    language_scope.clone(),
11097                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11098                ));
11099                row = next_paragraph_start;
11100            }
11101            ranges.push((
11102                language_settings.clone(),
11103                language_scope.clone(),
11104                Point::new(row, 0)..Point::new(end_row, 0),
11105            ));
11106
11107            ranges
11108        });
11109
11110        let mut edits = Vec::new();
11111        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11112
11113        for (language_settings, language_scope, range) in ranges {
11114            let mut start_row = range.start.row;
11115            let mut end_row = range.end.row;
11116
11117            // Skip selections that overlap with a range that has already been rewrapped.
11118            let selection_range = start_row..end_row;
11119            if rewrapped_row_ranges
11120                .iter()
11121                .any(|range| range.overlaps(&selection_range))
11122            {
11123                continue;
11124            }
11125
11126            let tab_size = language_settings.tab_size;
11127
11128            // Since not all lines in the selection may be at the same indent
11129            // level, choose the indent size that is the most common between all
11130            // of the lines.
11131            //
11132            // If there is a tie, we use the deepest indent.
11133            let (indent_size, indent_end) = {
11134                let mut indent_size_occurrences = HashMap::default();
11135                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11136
11137                for row in start_row..=end_row {
11138                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11139                    rows_by_indent_size.entry(indent).or_default().push(row);
11140                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11141                }
11142
11143                let indent_size = indent_size_occurrences
11144                    .into_iter()
11145                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11146                    .map(|(indent, _)| indent)
11147                    .unwrap_or_default();
11148                let row = rows_by_indent_size[&indent_size][0];
11149                let indent_end = Point::new(row, indent_size.len);
11150
11151                (indent_size, indent_end)
11152            };
11153
11154            let mut line_prefix = indent_size.chars().collect::<String>();
11155
11156            let mut inside_comment = false;
11157            if let Some(comment_prefix) = language_scope.and_then(|language| {
11158                language
11159                    .line_comment_prefixes()
11160                    .iter()
11161                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11162                    .cloned()
11163            }) {
11164                line_prefix.push_str(&comment_prefix);
11165                inside_comment = true;
11166            }
11167
11168            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11169                RewrapBehavior::InComments => inside_comment,
11170                RewrapBehavior::InSelections => !range.is_empty(),
11171                RewrapBehavior::Anywhere => true,
11172            };
11173
11174            let should_rewrap = options.override_language_settings
11175                || allow_rewrap_based_on_language
11176                || self.hard_wrap.is_some();
11177            if !should_rewrap {
11178                continue;
11179            }
11180
11181            if range.is_empty() {
11182                'expand_upwards: while start_row > 0 {
11183                    let prev_row = start_row - 1;
11184                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11185                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11186                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11187                    {
11188                        start_row = prev_row;
11189                    } else {
11190                        break 'expand_upwards;
11191                    }
11192                }
11193
11194                'expand_downwards: while end_row < buffer.max_point().row {
11195                    let next_row = end_row + 1;
11196                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11197                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11198                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11199                    {
11200                        end_row = next_row;
11201                    } else {
11202                        break 'expand_downwards;
11203                    }
11204                }
11205            }
11206
11207            let start = Point::new(start_row, 0);
11208            let start_offset = start.to_offset(&buffer);
11209            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11210            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11211            let Some(lines_without_prefixes) = selection_text
11212                .lines()
11213                .map(|line| {
11214                    line.strip_prefix(&line_prefix)
11215                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11216                        .with_context(|| {
11217                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11218                        })
11219                })
11220                .collect::<Result<Vec<_>, _>>()
11221                .log_err()
11222            else {
11223                continue;
11224            };
11225
11226            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11227                buffer
11228                    .language_settings_at(Point::new(start_row, 0), cx)
11229                    .preferred_line_length as usize
11230            });
11231            let wrapped_text = wrap_with_prefix(
11232                line_prefix,
11233                lines_without_prefixes.join("\n"),
11234                wrap_column,
11235                tab_size,
11236                options.preserve_existing_whitespace,
11237            );
11238
11239            // TODO: should always use char-based diff while still supporting cursor behavior that
11240            // matches vim.
11241            let mut diff_options = DiffOptions::default();
11242            if options.override_language_settings {
11243                diff_options.max_word_diff_len = 0;
11244                diff_options.max_word_diff_line_count = 0;
11245            } else {
11246                diff_options.max_word_diff_len = usize::MAX;
11247                diff_options.max_word_diff_line_count = usize::MAX;
11248            }
11249
11250            for (old_range, new_text) in
11251                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11252            {
11253                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11254                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11255                edits.push((edit_start..edit_end, new_text));
11256            }
11257
11258            rewrapped_row_ranges.push(start_row..=end_row);
11259        }
11260
11261        self.buffer
11262            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11263    }
11264
11265    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11266        let mut text = String::new();
11267        let buffer = self.buffer.read(cx).snapshot(cx);
11268        let mut selections = self.selections.all::<Point>(cx);
11269        let mut clipboard_selections = Vec::with_capacity(selections.len());
11270        {
11271            let max_point = buffer.max_point();
11272            let mut is_first = true;
11273            for selection in &mut selections {
11274                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11275                if is_entire_line {
11276                    selection.start = Point::new(selection.start.row, 0);
11277                    if !selection.is_empty() && selection.end.column == 0 {
11278                        selection.end = cmp::min(max_point, selection.end);
11279                    } else {
11280                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11281                    }
11282                    selection.goal = SelectionGoal::None;
11283                }
11284                if is_first {
11285                    is_first = false;
11286                } else {
11287                    text += "\n";
11288                }
11289                let mut len = 0;
11290                for chunk in buffer.text_for_range(selection.start..selection.end) {
11291                    text.push_str(chunk);
11292                    len += chunk.len();
11293                }
11294                clipboard_selections.push(ClipboardSelection {
11295                    len,
11296                    is_entire_line,
11297                    first_line_indent: buffer
11298                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11299                        .len,
11300                });
11301            }
11302        }
11303
11304        self.transact(window, cx, |this, window, cx| {
11305            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11306                s.select(selections);
11307            });
11308            this.insert("", window, cx);
11309        });
11310        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11311    }
11312
11313    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11314        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11315        let item = self.cut_common(window, cx);
11316        cx.write_to_clipboard(item);
11317    }
11318
11319    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11320        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11321        self.change_selections(None, window, cx, |s| {
11322            s.move_with(|snapshot, sel| {
11323                if sel.is_empty() {
11324                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11325                }
11326            });
11327        });
11328        let item = self.cut_common(window, cx);
11329        cx.set_global(KillRing(item))
11330    }
11331
11332    pub fn kill_ring_yank(
11333        &mut self,
11334        _: &KillRingYank,
11335        window: &mut Window,
11336        cx: &mut Context<Self>,
11337    ) {
11338        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11339        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11340            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11341                (kill_ring.text().to_string(), kill_ring.metadata_json())
11342            } else {
11343                return;
11344            }
11345        } else {
11346            return;
11347        };
11348        self.do_paste(&text, metadata, false, window, cx);
11349    }
11350
11351    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11352        self.do_copy(true, cx);
11353    }
11354
11355    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11356        self.do_copy(false, cx);
11357    }
11358
11359    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11360        let selections = self.selections.all::<Point>(cx);
11361        let buffer = self.buffer.read(cx).read(cx);
11362        let mut text = String::new();
11363
11364        let mut clipboard_selections = Vec::with_capacity(selections.len());
11365        {
11366            let max_point = buffer.max_point();
11367            let mut is_first = true;
11368            for selection in &selections {
11369                let mut start = selection.start;
11370                let mut end = selection.end;
11371                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11372                if is_entire_line {
11373                    start = Point::new(start.row, 0);
11374                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11375                }
11376
11377                let mut trimmed_selections = Vec::new();
11378                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11379                    let row = MultiBufferRow(start.row);
11380                    let first_indent = buffer.indent_size_for_line(row);
11381                    if first_indent.len == 0 || start.column > first_indent.len {
11382                        trimmed_selections.push(start..end);
11383                    } else {
11384                        trimmed_selections.push(
11385                            Point::new(row.0, first_indent.len)
11386                                ..Point::new(row.0, buffer.line_len(row)),
11387                        );
11388                        for row in start.row + 1..=end.row {
11389                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11390                            if row == end.row {
11391                                line_len = end.column;
11392                            }
11393                            if line_len == 0 {
11394                                trimmed_selections
11395                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11396                                continue;
11397                            }
11398                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11399                            if row_indent_size.len >= first_indent.len {
11400                                trimmed_selections.push(
11401                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11402                                );
11403                            } else {
11404                                trimmed_selections.clear();
11405                                trimmed_selections.push(start..end);
11406                                break;
11407                            }
11408                        }
11409                    }
11410                } else {
11411                    trimmed_selections.push(start..end);
11412                }
11413
11414                for trimmed_range in trimmed_selections {
11415                    if is_first {
11416                        is_first = false;
11417                    } else {
11418                        text += "\n";
11419                    }
11420                    let mut len = 0;
11421                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11422                        text.push_str(chunk);
11423                        len += chunk.len();
11424                    }
11425                    clipboard_selections.push(ClipboardSelection {
11426                        len,
11427                        is_entire_line,
11428                        first_line_indent: buffer
11429                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11430                            .len,
11431                    });
11432                }
11433            }
11434        }
11435
11436        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11437            text,
11438            clipboard_selections,
11439        ));
11440    }
11441
11442    pub fn do_paste(
11443        &mut self,
11444        text: &String,
11445        clipboard_selections: Option<Vec<ClipboardSelection>>,
11446        handle_entire_lines: bool,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        if self.read_only(cx) {
11451            return;
11452        }
11453
11454        let clipboard_text = Cow::Borrowed(text);
11455
11456        self.transact(window, cx, |this, window, cx| {
11457            if let Some(mut clipboard_selections) = clipboard_selections {
11458                let old_selections = this.selections.all::<usize>(cx);
11459                let all_selections_were_entire_line =
11460                    clipboard_selections.iter().all(|s| s.is_entire_line);
11461                let first_selection_indent_column =
11462                    clipboard_selections.first().map(|s| s.first_line_indent);
11463                if clipboard_selections.len() != old_selections.len() {
11464                    clipboard_selections.drain(..);
11465                }
11466                let cursor_offset = this.selections.last::<usize>(cx).head();
11467                let mut auto_indent_on_paste = true;
11468
11469                this.buffer.update(cx, |buffer, cx| {
11470                    let snapshot = buffer.read(cx);
11471                    auto_indent_on_paste = snapshot
11472                        .language_settings_at(cursor_offset, cx)
11473                        .auto_indent_on_paste;
11474
11475                    let mut start_offset = 0;
11476                    let mut edits = Vec::new();
11477                    let mut original_indent_columns = Vec::new();
11478                    for (ix, selection) in old_selections.iter().enumerate() {
11479                        let to_insert;
11480                        let entire_line;
11481                        let original_indent_column;
11482                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11483                            let end_offset = start_offset + clipboard_selection.len;
11484                            to_insert = &clipboard_text[start_offset..end_offset];
11485                            entire_line = clipboard_selection.is_entire_line;
11486                            start_offset = end_offset + 1;
11487                            original_indent_column = Some(clipboard_selection.first_line_indent);
11488                        } else {
11489                            to_insert = clipboard_text.as_str();
11490                            entire_line = all_selections_were_entire_line;
11491                            original_indent_column = first_selection_indent_column
11492                        }
11493
11494                        // If the corresponding selection was empty when this slice of the
11495                        // clipboard text was written, then the entire line containing the
11496                        // selection was copied. If this selection is also currently empty,
11497                        // then paste the line before the current line of the buffer.
11498                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11499                            let column = selection.start.to_point(&snapshot).column as usize;
11500                            let line_start = selection.start - column;
11501                            line_start..line_start
11502                        } else {
11503                            selection.range()
11504                        };
11505
11506                        edits.push((range, to_insert));
11507                        original_indent_columns.push(original_indent_column);
11508                    }
11509                    drop(snapshot);
11510
11511                    buffer.edit(
11512                        edits,
11513                        if auto_indent_on_paste {
11514                            Some(AutoindentMode::Block {
11515                                original_indent_columns,
11516                            })
11517                        } else {
11518                            None
11519                        },
11520                        cx,
11521                    );
11522                });
11523
11524                let selections = this.selections.all::<usize>(cx);
11525                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11526                    s.select(selections)
11527                });
11528            } else {
11529                this.insert(&clipboard_text, window, cx);
11530            }
11531        });
11532    }
11533
11534    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11535        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11536        if let Some(item) = cx.read_from_clipboard() {
11537            let entries = item.entries();
11538
11539            match entries.first() {
11540                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11541                // of all the pasted entries.
11542                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11543                    .do_paste(
11544                        clipboard_string.text(),
11545                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11546                        true,
11547                        window,
11548                        cx,
11549                    ),
11550                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11551            }
11552        }
11553    }
11554
11555    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11556        if self.read_only(cx) {
11557            return;
11558        }
11559
11560        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11561
11562        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11563            if let Some((selections, _)) =
11564                self.selection_history.transaction(transaction_id).cloned()
11565            {
11566                self.change_selections(None, window, cx, |s| {
11567                    s.select_anchors(selections.to_vec());
11568                });
11569            } else {
11570                log::error!(
11571                    "No entry in selection_history found for undo. \
11572                     This may correspond to a bug where undo does not update the selection. \
11573                     If this is occurring, please add details to \
11574                     https://github.com/zed-industries/zed/issues/22692"
11575                );
11576            }
11577            self.request_autoscroll(Autoscroll::fit(), cx);
11578            self.unmark_text(window, cx);
11579            self.refresh_inline_completion(true, false, window, cx);
11580            cx.emit(EditorEvent::Edited { transaction_id });
11581            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11582        }
11583    }
11584
11585    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11586        if self.read_only(cx) {
11587            return;
11588        }
11589
11590        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11591
11592        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11593            if let Some((_, Some(selections))) =
11594                self.selection_history.transaction(transaction_id).cloned()
11595            {
11596                self.change_selections(None, window, cx, |s| {
11597                    s.select_anchors(selections.to_vec());
11598                });
11599            } else {
11600                log::error!(
11601                    "No entry in selection_history found for redo. \
11602                     This may correspond to a bug where undo does not update the selection. \
11603                     If this is occurring, please add details to \
11604                     https://github.com/zed-industries/zed/issues/22692"
11605                );
11606            }
11607            self.request_autoscroll(Autoscroll::fit(), cx);
11608            self.unmark_text(window, cx);
11609            self.refresh_inline_completion(true, false, window, cx);
11610            cx.emit(EditorEvent::Edited { transaction_id });
11611        }
11612    }
11613
11614    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11615        self.buffer
11616            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11617    }
11618
11619    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11620        self.buffer
11621            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11622    }
11623
11624    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11625        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11626        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11627            s.move_with(|map, selection| {
11628                let cursor = if selection.is_empty() {
11629                    movement::left(map, selection.start)
11630                } else {
11631                    selection.start
11632                };
11633                selection.collapse_to(cursor, SelectionGoal::None);
11634            });
11635        })
11636    }
11637
11638    pub fn select_left(&mut self, _: &SelectLeft, 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_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11642        })
11643    }
11644
11645    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11646        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11647        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11648            s.move_with(|map, selection| {
11649                let cursor = if selection.is_empty() {
11650                    movement::right(map, selection.end)
11651                } else {
11652                    selection.end
11653                };
11654                selection.collapse_to(cursor, SelectionGoal::None)
11655            });
11656        })
11657    }
11658
11659    pub fn select_right(&mut self, _: &SelectRight, 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_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11663        })
11664    }
11665
11666    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11667        if self.take_rename(true, window, cx).is_some() {
11668            return;
11669        }
11670
11671        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11672            cx.propagate();
11673            return;
11674        }
11675
11676        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11677
11678        let text_layout_details = &self.text_layout_details(window);
11679        let selection_count = self.selections.count();
11680        let first_selection = self.selections.first_anchor();
11681
11682        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11683            s.move_with(|map, selection| {
11684                if !selection.is_empty() {
11685                    selection.goal = SelectionGoal::None;
11686                }
11687                let (cursor, goal) = movement::up(
11688                    map,
11689                    selection.start,
11690                    selection.goal,
11691                    false,
11692                    text_layout_details,
11693                );
11694                selection.collapse_to(cursor, goal);
11695            });
11696        });
11697
11698        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11699        {
11700            cx.propagate();
11701        }
11702    }
11703
11704    pub fn move_up_by_lines(
11705        &mut self,
11706        action: &MoveUpByLines,
11707        window: &mut Window,
11708        cx: &mut Context<Self>,
11709    ) {
11710        if self.take_rename(true, window, cx).is_some() {
11711            return;
11712        }
11713
11714        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11715            cx.propagate();
11716            return;
11717        }
11718
11719        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11720
11721        let text_layout_details = &self.text_layout_details(window);
11722
11723        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11724            s.move_with(|map, selection| {
11725                if !selection.is_empty() {
11726                    selection.goal = SelectionGoal::None;
11727                }
11728                let (cursor, goal) = movement::up_by_rows(
11729                    map,
11730                    selection.start,
11731                    action.lines,
11732                    selection.goal,
11733                    false,
11734                    text_layout_details,
11735                );
11736                selection.collapse_to(cursor, goal);
11737            });
11738        })
11739    }
11740
11741    pub fn move_down_by_lines(
11742        &mut self,
11743        action: &MoveDownByLines,
11744        window: &mut Window,
11745        cx: &mut Context<Self>,
11746    ) {
11747        if self.take_rename(true, window, cx).is_some() {
11748            return;
11749        }
11750
11751        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11752            cx.propagate();
11753            return;
11754        }
11755
11756        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11757
11758        let text_layout_details = &self.text_layout_details(window);
11759
11760        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11761            s.move_with(|map, selection| {
11762                if !selection.is_empty() {
11763                    selection.goal = SelectionGoal::None;
11764                }
11765                let (cursor, goal) = movement::down_by_rows(
11766                    map,
11767                    selection.start,
11768                    action.lines,
11769                    selection.goal,
11770                    false,
11771                    text_layout_details,
11772                );
11773                selection.collapse_to(cursor, goal);
11774            });
11775        })
11776    }
11777
11778    pub fn select_down_by_lines(
11779        &mut self,
11780        action: &SelectDownByLines,
11781        window: &mut Window,
11782        cx: &mut Context<Self>,
11783    ) {
11784        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11785        let text_layout_details = &self.text_layout_details(window);
11786        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11787            s.move_heads_with(|map, head, goal| {
11788                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11789            })
11790        })
11791    }
11792
11793    pub fn select_up_by_lines(
11794        &mut self,
11795        action: &SelectUpByLines,
11796        window: &mut Window,
11797        cx: &mut Context<Self>,
11798    ) {
11799        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11800        let text_layout_details = &self.text_layout_details(window);
11801        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11802            s.move_heads_with(|map, head, goal| {
11803                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11804            })
11805        })
11806    }
11807
11808    pub fn select_page_up(
11809        &mut self,
11810        _: &SelectPageUp,
11811        window: &mut Window,
11812        cx: &mut Context<Self>,
11813    ) {
11814        let Some(row_count) = self.visible_row_count() else {
11815            return;
11816        };
11817
11818        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11819
11820        let text_layout_details = &self.text_layout_details(window);
11821
11822        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11823            s.move_heads_with(|map, head, goal| {
11824                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11825            })
11826        })
11827    }
11828
11829    pub fn move_page_up(
11830        &mut self,
11831        action: &MovePageUp,
11832        window: &mut Window,
11833        cx: &mut Context<Self>,
11834    ) {
11835        if self.take_rename(true, window, cx).is_some() {
11836            return;
11837        }
11838
11839        if self
11840            .context_menu
11841            .borrow_mut()
11842            .as_mut()
11843            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11844            .unwrap_or(false)
11845        {
11846            return;
11847        }
11848
11849        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11850            cx.propagate();
11851            return;
11852        }
11853
11854        let Some(row_count) = self.visible_row_count() else {
11855            return;
11856        };
11857
11858        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11859
11860        let autoscroll = if action.center_cursor {
11861            Autoscroll::center()
11862        } else {
11863            Autoscroll::fit()
11864        };
11865
11866        let text_layout_details = &self.text_layout_details(window);
11867
11868        self.change_selections(Some(autoscroll), window, cx, |s| {
11869            s.move_with(|map, selection| {
11870                if !selection.is_empty() {
11871                    selection.goal = SelectionGoal::None;
11872                }
11873                let (cursor, goal) = movement::up_by_rows(
11874                    map,
11875                    selection.end,
11876                    row_count,
11877                    selection.goal,
11878                    false,
11879                    text_layout_details,
11880                );
11881                selection.collapse_to(cursor, goal);
11882            });
11883        });
11884    }
11885
11886    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11887        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11888        let text_layout_details = &self.text_layout_details(window);
11889        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11890            s.move_heads_with(|map, head, goal| {
11891                movement::up(map, head, goal, false, text_layout_details)
11892            })
11893        })
11894    }
11895
11896    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11897        self.take_rename(true, window, cx);
11898
11899        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11900            cx.propagate();
11901            return;
11902        }
11903
11904        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11905
11906        let text_layout_details = &self.text_layout_details(window);
11907        let selection_count = self.selections.count();
11908        let first_selection = self.selections.first_anchor();
11909
11910        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11911            s.move_with(|map, selection| {
11912                if !selection.is_empty() {
11913                    selection.goal = SelectionGoal::None;
11914                }
11915                let (cursor, goal) = movement::down(
11916                    map,
11917                    selection.end,
11918                    selection.goal,
11919                    false,
11920                    text_layout_details,
11921                );
11922                selection.collapse_to(cursor, goal);
11923            });
11924        });
11925
11926        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11927        {
11928            cx.propagate();
11929        }
11930    }
11931
11932    pub fn select_page_down(
11933        &mut self,
11934        _: &SelectPageDown,
11935        window: &mut Window,
11936        cx: &mut Context<Self>,
11937    ) {
11938        let Some(row_count) = self.visible_row_count() else {
11939            return;
11940        };
11941
11942        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11943
11944        let text_layout_details = &self.text_layout_details(window);
11945
11946        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11947            s.move_heads_with(|map, head, goal| {
11948                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11949            })
11950        })
11951    }
11952
11953    pub fn move_page_down(
11954        &mut self,
11955        action: &MovePageDown,
11956        window: &mut Window,
11957        cx: &mut Context<Self>,
11958    ) {
11959        if self.take_rename(true, window, cx).is_some() {
11960            return;
11961        }
11962
11963        if self
11964            .context_menu
11965            .borrow_mut()
11966            .as_mut()
11967            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11968            .unwrap_or(false)
11969        {
11970            return;
11971        }
11972
11973        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11974            cx.propagate();
11975            return;
11976        }
11977
11978        let Some(row_count) = self.visible_row_count() else {
11979            return;
11980        };
11981
11982        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11983
11984        let autoscroll = if action.center_cursor {
11985            Autoscroll::center()
11986        } else {
11987            Autoscroll::fit()
11988        };
11989
11990        let text_layout_details = &self.text_layout_details(window);
11991        self.change_selections(Some(autoscroll), window, cx, |s| {
11992            s.move_with(|map, selection| {
11993                if !selection.is_empty() {
11994                    selection.goal = SelectionGoal::None;
11995                }
11996                let (cursor, goal) = movement::down_by_rows(
11997                    map,
11998                    selection.end,
11999                    row_count,
12000                    selection.goal,
12001                    false,
12002                    text_layout_details,
12003                );
12004                selection.collapse_to(cursor, goal);
12005            });
12006        });
12007    }
12008
12009    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12010        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12011        let text_layout_details = &self.text_layout_details(window);
12012        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12013            s.move_heads_with(|map, head, goal| {
12014                movement::down(map, head, goal, false, text_layout_details)
12015            })
12016        });
12017    }
12018
12019    pub fn context_menu_first(
12020        &mut self,
12021        _: &ContextMenuFirst,
12022        window: &mut Window,
12023        cx: &mut Context<Self>,
12024    ) {
12025        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12026            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12027        }
12028    }
12029
12030    pub fn context_menu_prev(
12031        &mut self,
12032        _: &ContextMenuPrevious,
12033        window: &mut Window,
12034        cx: &mut Context<Self>,
12035    ) {
12036        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12037            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12038        }
12039    }
12040
12041    pub fn context_menu_next(
12042        &mut self,
12043        _: &ContextMenuNext,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12048            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12049        }
12050    }
12051
12052    pub fn context_menu_last(
12053        &mut self,
12054        _: &ContextMenuLast,
12055        window: &mut Window,
12056        cx: &mut Context<Self>,
12057    ) {
12058        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12059            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12060        }
12061    }
12062
12063    pub fn move_to_previous_word_start(
12064        &mut self,
12065        _: &MoveToPreviousWordStart,
12066        window: &mut Window,
12067        cx: &mut Context<Self>,
12068    ) {
12069        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12070        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12071            s.move_cursors_with(|map, head, _| {
12072                (
12073                    movement::previous_word_start(map, head),
12074                    SelectionGoal::None,
12075                )
12076            });
12077        })
12078    }
12079
12080    pub fn move_to_previous_subword_start(
12081        &mut self,
12082        _: &MoveToPreviousSubwordStart,
12083        window: &mut Window,
12084        cx: &mut Context<Self>,
12085    ) {
12086        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12087        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12088            s.move_cursors_with(|map, head, _| {
12089                (
12090                    movement::previous_subword_start(map, head),
12091                    SelectionGoal::None,
12092                )
12093            });
12094        })
12095    }
12096
12097    pub fn select_to_previous_word_start(
12098        &mut self,
12099        _: &SelectToPreviousWordStart,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12104        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12105            s.move_heads_with(|map, head, _| {
12106                (
12107                    movement::previous_word_start(map, head),
12108                    SelectionGoal::None,
12109                )
12110            });
12111        })
12112    }
12113
12114    pub fn select_to_previous_subword_start(
12115        &mut self,
12116        _: &SelectToPreviousSubwordStart,
12117        window: &mut Window,
12118        cx: &mut Context<Self>,
12119    ) {
12120        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12121        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12122            s.move_heads_with(|map, head, _| {
12123                (
12124                    movement::previous_subword_start(map, head),
12125                    SelectionGoal::None,
12126                )
12127            });
12128        })
12129    }
12130
12131    pub fn delete_to_previous_word_start(
12132        &mut self,
12133        action: &DeleteToPreviousWordStart,
12134        window: &mut Window,
12135        cx: &mut Context<Self>,
12136    ) {
12137        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12138        self.transact(window, cx, |this, window, cx| {
12139            this.select_autoclose_pair(window, cx);
12140            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141                s.move_with(|map, selection| {
12142                    if selection.is_empty() {
12143                        let cursor = if action.ignore_newlines {
12144                            movement::previous_word_start(map, selection.head())
12145                        } else {
12146                            movement::previous_word_start_or_newline(map, selection.head())
12147                        };
12148                        selection.set_head(cursor, SelectionGoal::None);
12149                    }
12150                });
12151            });
12152            this.insert("", window, cx);
12153        });
12154    }
12155
12156    pub fn delete_to_previous_subword_start(
12157        &mut self,
12158        _: &DeleteToPreviousSubwordStart,
12159        window: &mut Window,
12160        cx: &mut Context<Self>,
12161    ) {
12162        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12163        self.transact(window, cx, |this, window, cx| {
12164            this.select_autoclose_pair(window, cx);
12165            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12166                s.move_with(|map, selection| {
12167                    if selection.is_empty() {
12168                        let cursor = movement::previous_subword_start(map, selection.head());
12169                        selection.set_head(cursor, SelectionGoal::None);
12170                    }
12171                });
12172            });
12173            this.insert("", window, cx);
12174        });
12175    }
12176
12177    pub fn move_to_next_word_end(
12178        &mut self,
12179        _: &MoveToNextWordEnd,
12180        window: &mut Window,
12181        cx: &mut Context<Self>,
12182    ) {
12183        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12184        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12185            s.move_cursors_with(|map, head, _| {
12186                (movement::next_word_end(map, head), SelectionGoal::None)
12187            });
12188        })
12189    }
12190
12191    pub fn move_to_next_subword_end(
12192        &mut self,
12193        _: &MoveToNextSubwordEnd,
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_subword_end(map, head), SelectionGoal::None)
12201            });
12202        })
12203    }
12204
12205    pub fn select_to_next_word_end(
12206        &mut self,
12207        _: &SelectToNextWordEnd,
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_heads_with(|map, head, _| {
12214                (movement::next_word_end(map, head), SelectionGoal::None)
12215            });
12216        })
12217    }
12218
12219    pub fn select_to_next_subword_end(
12220        &mut self,
12221        _: &SelectToNextSubwordEnd,
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_subword_end(map, head), SelectionGoal::None)
12229            });
12230        })
12231    }
12232
12233    pub fn delete_to_next_word_end(
12234        &mut self,
12235        action: &DeleteToNextWordEnd,
12236        window: &mut Window,
12237        cx: &mut Context<Self>,
12238    ) {
12239        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12240        self.transact(window, cx, |this, window, cx| {
12241            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12242                s.move_with(|map, selection| {
12243                    if selection.is_empty() {
12244                        let cursor = if action.ignore_newlines {
12245                            movement::next_word_end(map, selection.head())
12246                        } else {
12247                            movement::next_word_end_or_newline(map, selection.head())
12248                        };
12249                        selection.set_head(cursor, SelectionGoal::None);
12250                    }
12251                });
12252            });
12253            this.insert("", window, cx);
12254        });
12255    }
12256
12257    pub fn delete_to_next_subword_end(
12258        &mut self,
12259        _: &DeleteToNextSubwordEnd,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) {
12263        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12264        self.transact(window, cx, |this, window, cx| {
12265            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12266                s.move_with(|map, selection| {
12267                    if selection.is_empty() {
12268                        let cursor = movement::next_subword_end(map, selection.head());
12269                        selection.set_head(cursor, SelectionGoal::None);
12270                    }
12271                });
12272            });
12273            this.insert("", window, cx);
12274        });
12275    }
12276
12277    pub fn move_to_beginning_of_line(
12278        &mut self,
12279        action: &MoveToBeginningOfLine,
12280        window: &mut Window,
12281        cx: &mut Context<Self>,
12282    ) {
12283        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12284        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12285            s.move_cursors_with(|map, head, _| {
12286                (
12287                    movement::indented_line_beginning(
12288                        map,
12289                        head,
12290                        action.stop_at_soft_wraps,
12291                        action.stop_at_indent,
12292                    ),
12293                    SelectionGoal::None,
12294                )
12295            });
12296        })
12297    }
12298
12299    pub fn select_to_beginning_of_line(
12300        &mut self,
12301        action: &SelectToBeginningOfLine,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12306        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12307            s.move_heads_with(|map, head, _| {
12308                (
12309                    movement::indented_line_beginning(
12310                        map,
12311                        head,
12312                        action.stop_at_soft_wraps,
12313                        action.stop_at_indent,
12314                    ),
12315                    SelectionGoal::None,
12316                )
12317            });
12318        });
12319    }
12320
12321    pub fn delete_to_beginning_of_line(
12322        &mut self,
12323        action: &DeleteToBeginningOfLine,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) {
12327        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12328        self.transact(window, cx, |this, window, cx| {
12329            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12330                s.move_with(|_, selection| {
12331                    selection.reversed = true;
12332                });
12333            });
12334
12335            this.select_to_beginning_of_line(
12336                &SelectToBeginningOfLine {
12337                    stop_at_soft_wraps: false,
12338                    stop_at_indent: action.stop_at_indent,
12339                },
12340                window,
12341                cx,
12342            );
12343            this.backspace(&Backspace, window, cx);
12344        });
12345    }
12346
12347    pub fn move_to_end_of_line(
12348        &mut self,
12349        action: &MoveToEndOfLine,
12350        window: &mut Window,
12351        cx: &mut Context<Self>,
12352    ) {
12353        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12354        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12355            s.move_cursors_with(|map, head, _| {
12356                (
12357                    movement::line_end(map, head, action.stop_at_soft_wraps),
12358                    SelectionGoal::None,
12359                )
12360            });
12361        })
12362    }
12363
12364    pub fn select_to_end_of_line(
12365        &mut self,
12366        action: &SelectToEndOfLine,
12367        window: &mut Window,
12368        cx: &mut Context<Self>,
12369    ) {
12370        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12371        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12372            s.move_heads_with(|map, head, _| {
12373                (
12374                    movement::line_end(map, head, action.stop_at_soft_wraps),
12375                    SelectionGoal::None,
12376                )
12377            });
12378        })
12379    }
12380
12381    pub fn delete_to_end_of_line(
12382        &mut self,
12383        _: &DeleteToEndOfLine,
12384        window: &mut Window,
12385        cx: &mut Context<Self>,
12386    ) {
12387        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12388        self.transact(window, cx, |this, window, cx| {
12389            this.select_to_end_of_line(
12390                &SelectToEndOfLine {
12391                    stop_at_soft_wraps: false,
12392                },
12393                window,
12394                cx,
12395            );
12396            this.delete(&Delete, window, cx);
12397        });
12398    }
12399
12400    pub fn cut_to_end_of_line(
12401        &mut self,
12402        _: &CutToEndOfLine,
12403        window: &mut Window,
12404        cx: &mut Context<Self>,
12405    ) {
12406        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12407        self.transact(window, cx, |this, window, cx| {
12408            this.select_to_end_of_line(
12409                &SelectToEndOfLine {
12410                    stop_at_soft_wraps: false,
12411                },
12412                window,
12413                cx,
12414            );
12415            this.cut(&Cut, window, cx);
12416        });
12417    }
12418
12419    pub fn move_to_start_of_paragraph(
12420        &mut self,
12421        _: &MoveToStartOfParagraph,
12422        window: &mut Window,
12423        cx: &mut Context<Self>,
12424    ) {
12425        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12426            cx.propagate();
12427            return;
12428        }
12429        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12430        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12431            s.move_with(|map, selection| {
12432                selection.collapse_to(
12433                    movement::start_of_paragraph(map, selection.head(), 1),
12434                    SelectionGoal::None,
12435                )
12436            });
12437        })
12438    }
12439
12440    pub fn move_to_end_of_paragraph(
12441        &mut self,
12442        _: &MoveToEndOfParagraph,
12443        window: &mut Window,
12444        cx: &mut Context<Self>,
12445    ) {
12446        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12447            cx.propagate();
12448            return;
12449        }
12450        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12451        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12452            s.move_with(|map, selection| {
12453                selection.collapse_to(
12454                    movement::end_of_paragraph(map, selection.head(), 1),
12455                    SelectionGoal::None,
12456                )
12457            });
12458        })
12459    }
12460
12461    pub fn select_to_start_of_paragraph(
12462        &mut self,
12463        _: &SelectToStartOfParagraph,
12464        window: &mut Window,
12465        cx: &mut Context<Self>,
12466    ) {
12467        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12468            cx.propagate();
12469            return;
12470        }
12471        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12472        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12473            s.move_heads_with(|map, head, _| {
12474                (
12475                    movement::start_of_paragraph(map, head, 1),
12476                    SelectionGoal::None,
12477                )
12478            });
12479        })
12480    }
12481
12482    pub fn select_to_end_of_paragraph(
12483        &mut self,
12484        _: &SelectToEndOfParagraph,
12485        window: &mut Window,
12486        cx: &mut Context<Self>,
12487    ) {
12488        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12489            cx.propagate();
12490            return;
12491        }
12492        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12493        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12494            s.move_heads_with(|map, head, _| {
12495                (
12496                    movement::end_of_paragraph(map, head, 1),
12497                    SelectionGoal::None,
12498                )
12499            });
12500        })
12501    }
12502
12503    pub fn move_to_start_of_excerpt(
12504        &mut self,
12505        _: &MoveToStartOfExcerpt,
12506        window: &mut Window,
12507        cx: &mut Context<Self>,
12508    ) {
12509        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12510            cx.propagate();
12511            return;
12512        }
12513        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12514        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12515            s.move_with(|map, selection| {
12516                selection.collapse_to(
12517                    movement::start_of_excerpt(
12518                        map,
12519                        selection.head(),
12520                        workspace::searchable::Direction::Prev,
12521                    ),
12522                    SelectionGoal::None,
12523                )
12524            });
12525        })
12526    }
12527
12528    pub fn move_to_start_of_next_excerpt(
12529        &mut self,
12530        _: &MoveToStartOfNextExcerpt,
12531        window: &mut Window,
12532        cx: &mut Context<Self>,
12533    ) {
12534        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12535            cx.propagate();
12536            return;
12537        }
12538
12539        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12540            s.move_with(|map, selection| {
12541                selection.collapse_to(
12542                    movement::start_of_excerpt(
12543                        map,
12544                        selection.head(),
12545                        workspace::searchable::Direction::Next,
12546                    ),
12547                    SelectionGoal::None,
12548                )
12549            });
12550        })
12551    }
12552
12553    pub fn move_to_end_of_excerpt(
12554        &mut self,
12555        _: &MoveToEndOfExcerpt,
12556        window: &mut Window,
12557        cx: &mut Context<Self>,
12558    ) {
12559        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12560            cx.propagate();
12561            return;
12562        }
12563        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12564        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12565            s.move_with(|map, selection| {
12566                selection.collapse_to(
12567                    movement::end_of_excerpt(
12568                        map,
12569                        selection.head(),
12570                        workspace::searchable::Direction::Next,
12571                    ),
12572                    SelectionGoal::None,
12573                )
12574            });
12575        })
12576    }
12577
12578    pub fn move_to_end_of_previous_excerpt(
12579        &mut self,
12580        _: &MoveToEndOfPreviousExcerpt,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12585            cx.propagate();
12586            return;
12587        }
12588        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12589        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12590            s.move_with(|map, selection| {
12591                selection.collapse_to(
12592                    movement::end_of_excerpt(
12593                        map,
12594                        selection.head(),
12595                        workspace::searchable::Direction::Prev,
12596                    ),
12597                    SelectionGoal::None,
12598                )
12599            });
12600        })
12601    }
12602
12603    pub fn select_to_start_of_excerpt(
12604        &mut self,
12605        _: &SelectToStartOfExcerpt,
12606        window: &mut Window,
12607        cx: &mut Context<Self>,
12608    ) {
12609        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12610            cx.propagate();
12611            return;
12612        }
12613        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12614        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12615            s.move_heads_with(|map, head, _| {
12616                (
12617                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12618                    SelectionGoal::None,
12619                )
12620            });
12621        })
12622    }
12623
12624    pub fn select_to_start_of_next_excerpt(
12625        &mut self,
12626        _: &SelectToStartOfNextExcerpt,
12627        window: &mut Window,
12628        cx: &mut Context<Self>,
12629    ) {
12630        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12631            cx.propagate();
12632            return;
12633        }
12634        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12635        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12636            s.move_heads_with(|map, head, _| {
12637                (
12638                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12639                    SelectionGoal::None,
12640                )
12641            });
12642        })
12643    }
12644
12645    pub fn select_to_end_of_excerpt(
12646        &mut self,
12647        _: &SelectToEndOfExcerpt,
12648        window: &mut Window,
12649        cx: &mut Context<Self>,
12650    ) {
12651        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12652            cx.propagate();
12653            return;
12654        }
12655        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12656        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12657            s.move_heads_with(|map, head, _| {
12658                (
12659                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12660                    SelectionGoal::None,
12661                )
12662            });
12663        })
12664    }
12665
12666    pub fn select_to_end_of_previous_excerpt(
12667        &mut self,
12668        _: &SelectToEndOfPreviousExcerpt,
12669        window: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) {
12672        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12673            cx.propagate();
12674            return;
12675        }
12676        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12677        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12678            s.move_heads_with(|map, head, _| {
12679                (
12680                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12681                    SelectionGoal::None,
12682                )
12683            });
12684        })
12685    }
12686
12687    pub fn move_to_beginning(
12688        &mut self,
12689        _: &MoveToBeginning,
12690        window: &mut Window,
12691        cx: &mut Context<Self>,
12692    ) {
12693        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12694            cx.propagate();
12695            return;
12696        }
12697        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12698        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12699            s.select_ranges(vec![0..0]);
12700        });
12701    }
12702
12703    pub fn select_to_beginning(
12704        &mut self,
12705        _: &SelectToBeginning,
12706        window: &mut Window,
12707        cx: &mut Context<Self>,
12708    ) {
12709        let mut selection = self.selections.last::<Point>(cx);
12710        selection.set_head(Point::zero(), SelectionGoal::None);
12711        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12712        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12713            s.select(vec![selection]);
12714        });
12715    }
12716
12717    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12718        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12719            cx.propagate();
12720            return;
12721        }
12722        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12723        let cursor = self.buffer.read(cx).read(cx).len();
12724        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12725            s.select_ranges(vec![cursor..cursor])
12726        });
12727    }
12728
12729    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12730        self.nav_history = nav_history;
12731    }
12732
12733    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12734        self.nav_history.as_ref()
12735    }
12736
12737    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12738        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12739    }
12740
12741    fn push_to_nav_history(
12742        &mut self,
12743        cursor_anchor: Anchor,
12744        new_position: Option<Point>,
12745        is_deactivate: bool,
12746        cx: &mut Context<Self>,
12747    ) {
12748        if let Some(nav_history) = self.nav_history.as_mut() {
12749            let buffer = self.buffer.read(cx).read(cx);
12750            let cursor_position = cursor_anchor.to_point(&buffer);
12751            let scroll_state = self.scroll_manager.anchor();
12752            let scroll_top_row = scroll_state.top_row(&buffer);
12753            drop(buffer);
12754
12755            if let Some(new_position) = new_position {
12756                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12757                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12758                    return;
12759                }
12760            }
12761
12762            nav_history.push(
12763                Some(NavigationData {
12764                    cursor_anchor,
12765                    cursor_position,
12766                    scroll_anchor: scroll_state,
12767                    scroll_top_row,
12768                }),
12769                cx,
12770            );
12771            cx.emit(EditorEvent::PushedToNavHistory {
12772                anchor: cursor_anchor,
12773                is_deactivate,
12774            })
12775        }
12776    }
12777
12778    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12779        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12780        let buffer = self.buffer.read(cx).snapshot(cx);
12781        let mut selection = self.selections.first::<usize>(cx);
12782        selection.set_head(buffer.len(), SelectionGoal::None);
12783        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12784            s.select(vec![selection]);
12785        });
12786    }
12787
12788    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12789        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12790        let end = self.buffer.read(cx).read(cx).len();
12791        self.change_selections(None, window, cx, |s| {
12792            s.select_ranges(vec![0..end]);
12793        });
12794    }
12795
12796    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12797        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12798        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12799        let mut selections = self.selections.all::<Point>(cx);
12800        let max_point = display_map.buffer_snapshot.max_point();
12801        for selection in &mut selections {
12802            let rows = selection.spanned_rows(true, &display_map);
12803            selection.start = Point::new(rows.start.0, 0);
12804            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12805            selection.reversed = false;
12806        }
12807        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12808            s.select(selections);
12809        });
12810    }
12811
12812    pub fn split_selection_into_lines(
12813        &mut self,
12814        _: &SplitSelectionIntoLines,
12815        window: &mut Window,
12816        cx: &mut Context<Self>,
12817    ) {
12818        let selections = self
12819            .selections
12820            .all::<Point>(cx)
12821            .into_iter()
12822            .map(|selection| selection.start..selection.end)
12823            .collect::<Vec<_>>();
12824        self.unfold_ranges(&selections, true, true, cx);
12825
12826        let mut new_selection_ranges = Vec::new();
12827        {
12828            let buffer = self.buffer.read(cx).read(cx);
12829            for selection in selections {
12830                for row in selection.start.row..selection.end.row {
12831                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12832                    new_selection_ranges.push(cursor..cursor);
12833                }
12834
12835                let is_multiline_selection = selection.start.row != selection.end.row;
12836                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12837                // so this action feels more ergonomic when paired with other selection operations
12838                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12839                if !should_skip_last {
12840                    new_selection_ranges.push(selection.end..selection.end);
12841                }
12842            }
12843        }
12844        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12845            s.select_ranges(new_selection_ranges);
12846        });
12847    }
12848
12849    pub fn add_selection_above(
12850        &mut self,
12851        _: &AddSelectionAbove,
12852        window: &mut Window,
12853        cx: &mut Context<Self>,
12854    ) {
12855        self.add_selection(true, window, cx);
12856    }
12857
12858    pub fn add_selection_below(
12859        &mut self,
12860        _: &AddSelectionBelow,
12861        window: &mut Window,
12862        cx: &mut Context<Self>,
12863    ) {
12864        self.add_selection(false, window, cx);
12865    }
12866
12867    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12868        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12869
12870        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12871        let all_selections = self.selections.all::<Point>(cx);
12872        let text_layout_details = self.text_layout_details(window);
12873
12874        let (mut columnar_selections, new_selections_to_columnarize) = {
12875            if let Some(state) = self.add_selections_state.as_ref() {
12876                let columnar_selection_ids: HashSet<_> = state
12877                    .groups
12878                    .iter()
12879                    .flat_map(|group| group.stack.iter())
12880                    .copied()
12881                    .collect();
12882
12883                all_selections
12884                    .into_iter()
12885                    .partition(|s| columnar_selection_ids.contains(&s.id))
12886            } else {
12887                (Vec::new(), all_selections)
12888            }
12889        };
12890
12891        let mut state = self
12892            .add_selections_state
12893            .take()
12894            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12895
12896        for selection in new_selections_to_columnarize {
12897            let range = selection.display_range(&display_map).sorted();
12898            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12899            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12900            let positions = start_x.min(end_x)..start_x.max(end_x);
12901            let mut stack = Vec::new();
12902            for row in range.start.row().0..=range.end.row().0 {
12903                if let Some(selection) = self.selections.build_columnar_selection(
12904                    &display_map,
12905                    DisplayRow(row),
12906                    &positions,
12907                    selection.reversed,
12908                    &text_layout_details,
12909                ) {
12910                    stack.push(selection.id);
12911                    columnar_selections.push(selection);
12912                }
12913            }
12914            if !stack.is_empty() {
12915                if above {
12916                    stack.reverse();
12917                }
12918                state.groups.push(AddSelectionsGroup { above, stack });
12919            }
12920        }
12921
12922        let mut final_selections = Vec::new();
12923        let end_row = if above {
12924            DisplayRow(0)
12925        } else {
12926            display_map.max_point().row()
12927        };
12928
12929        let mut last_added_item_per_group = HashMap::default();
12930        for group in state.groups.iter_mut() {
12931            if let Some(last_id) = group.stack.last() {
12932                last_added_item_per_group.insert(*last_id, group);
12933            }
12934        }
12935
12936        for selection in columnar_selections {
12937            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12938                if above == group.above {
12939                    let range = selection.display_range(&display_map).sorted();
12940                    debug_assert_eq!(range.start.row(), range.end.row());
12941                    let mut row = range.start.row();
12942                    let positions =
12943                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12944                            px(start)..px(end)
12945                        } else {
12946                            let start_x =
12947                                display_map.x_for_display_point(range.start, &text_layout_details);
12948                            let end_x =
12949                                display_map.x_for_display_point(range.end, &text_layout_details);
12950                            start_x.min(end_x)..start_x.max(end_x)
12951                        };
12952
12953                    let mut maybe_new_selection = None;
12954                    while row != end_row {
12955                        if above {
12956                            row.0 -= 1;
12957                        } else {
12958                            row.0 += 1;
12959                        }
12960                        if let Some(new_selection) = self.selections.build_columnar_selection(
12961                            &display_map,
12962                            row,
12963                            &positions,
12964                            selection.reversed,
12965                            &text_layout_details,
12966                        ) {
12967                            maybe_new_selection = Some(new_selection);
12968                            break;
12969                        }
12970                    }
12971
12972                    if let Some(new_selection) = maybe_new_selection {
12973                        group.stack.push(new_selection.id);
12974                        if above {
12975                            final_selections.push(new_selection);
12976                            final_selections.push(selection);
12977                        } else {
12978                            final_selections.push(selection);
12979                            final_selections.push(new_selection);
12980                        }
12981                    } else {
12982                        final_selections.push(selection);
12983                    }
12984                } else {
12985                    group.stack.pop();
12986                }
12987            } else {
12988                final_selections.push(selection);
12989            }
12990        }
12991
12992        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12993            s.select(final_selections);
12994        });
12995
12996        let final_selection_ids: HashSet<_> = self
12997            .selections
12998            .all::<Point>(cx)
12999            .iter()
13000            .map(|s| s.id)
13001            .collect();
13002        state.groups.retain_mut(|group| {
13003            // selections might get merged above so we remove invalid items from stacks
13004            group.stack.retain(|id| final_selection_ids.contains(id));
13005
13006            // single selection in stack can be treated as initial state
13007            group.stack.len() > 1
13008        });
13009
13010        if !state.groups.is_empty() {
13011            self.add_selections_state = Some(state);
13012        }
13013    }
13014
13015    fn select_match_ranges(
13016        &mut self,
13017        range: Range<usize>,
13018        reversed: bool,
13019        replace_newest: bool,
13020        auto_scroll: Option<Autoscroll>,
13021        window: &mut Window,
13022        cx: &mut Context<Editor>,
13023    ) {
13024        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13025        self.change_selections(auto_scroll, window, cx, |s| {
13026            if replace_newest {
13027                s.delete(s.newest_anchor().id);
13028            }
13029            if reversed {
13030                s.insert_range(range.end..range.start);
13031            } else {
13032                s.insert_range(range);
13033            }
13034        });
13035    }
13036
13037    pub fn select_next_match_internal(
13038        &mut self,
13039        display_map: &DisplaySnapshot,
13040        replace_newest: bool,
13041        autoscroll: Option<Autoscroll>,
13042        window: &mut Window,
13043        cx: &mut Context<Self>,
13044    ) -> Result<()> {
13045        let buffer = &display_map.buffer_snapshot;
13046        let mut selections = self.selections.all::<usize>(cx);
13047        if let Some(mut select_next_state) = self.select_next_state.take() {
13048            let query = &select_next_state.query;
13049            if !select_next_state.done {
13050                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13051                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13052                let mut next_selected_range = None;
13053
13054                let bytes_after_last_selection =
13055                    buffer.bytes_in_range(last_selection.end..buffer.len());
13056                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13057                let query_matches = query
13058                    .stream_find_iter(bytes_after_last_selection)
13059                    .map(|result| (last_selection.end, result))
13060                    .chain(
13061                        query
13062                            .stream_find_iter(bytes_before_first_selection)
13063                            .map(|result| (0, result)),
13064                    );
13065
13066                for (start_offset, query_match) in query_matches {
13067                    let query_match = query_match.unwrap(); // can only fail due to I/O
13068                    let offset_range =
13069                        start_offset + query_match.start()..start_offset + query_match.end();
13070                    let display_range = offset_range.start.to_display_point(display_map)
13071                        ..offset_range.end.to_display_point(display_map);
13072
13073                    if !select_next_state.wordwise
13074                        || (!movement::is_inside_word(display_map, display_range.start)
13075                            && !movement::is_inside_word(display_map, display_range.end))
13076                    {
13077                        // TODO: This is n^2, because we might check all the selections
13078                        if !selections
13079                            .iter()
13080                            .any(|selection| selection.range().overlaps(&offset_range))
13081                        {
13082                            next_selected_range = Some(offset_range);
13083                            break;
13084                        }
13085                    }
13086                }
13087
13088                if let Some(next_selected_range) = next_selected_range {
13089                    self.select_match_ranges(
13090                        next_selected_range,
13091                        last_selection.reversed,
13092                        replace_newest,
13093                        autoscroll,
13094                        window,
13095                        cx,
13096                    );
13097                } else {
13098                    select_next_state.done = true;
13099                }
13100            }
13101
13102            self.select_next_state = Some(select_next_state);
13103        } else {
13104            let mut only_carets = true;
13105            let mut same_text_selected = true;
13106            let mut selected_text = None;
13107
13108            let mut selections_iter = selections.iter().peekable();
13109            while let Some(selection) = selections_iter.next() {
13110                if selection.start != selection.end {
13111                    only_carets = false;
13112                }
13113
13114                if same_text_selected {
13115                    if selected_text.is_none() {
13116                        selected_text =
13117                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13118                    }
13119
13120                    if let Some(next_selection) = selections_iter.peek() {
13121                        if next_selection.range().len() == selection.range().len() {
13122                            let next_selected_text = buffer
13123                                .text_for_range(next_selection.range())
13124                                .collect::<String>();
13125                            if Some(next_selected_text) != selected_text {
13126                                same_text_selected = false;
13127                                selected_text = None;
13128                            }
13129                        } else {
13130                            same_text_selected = false;
13131                            selected_text = None;
13132                        }
13133                    }
13134                }
13135            }
13136
13137            if only_carets {
13138                for selection in &mut selections {
13139                    let word_range = movement::surrounding_word(
13140                        display_map,
13141                        selection.start.to_display_point(display_map),
13142                    );
13143                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13144                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13145                    selection.goal = SelectionGoal::None;
13146                    selection.reversed = false;
13147                    self.select_match_ranges(
13148                        selection.start..selection.end,
13149                        selection.reversed,
13150                        replace_newest,
13151                        autoscroll,
13152                        window,
13153                        cx,
13154                    );
13155                }
13156
13157                if selections.len() == 1 {
13158                    let selection = selections
13159                        .last()
13160                        .expect("ensured that there's only one selection");
13161                    let query = buffer
13162                        .text_for_range(selection.start..selection.end)
13163                        .collect::<String>();
13164                    let is_empty = query.is_empty();
13165                    let select_state = SelectNextState {
13166                        query: AhoCorasick::new(&[query])?,
13167                        wordwise: true,
13168                        done: is_empty,
13169                    };
13170                    self.select_next_state = Some(select_state);
13171                } else {
13172                    self.select_next_state = None;
13173                }
13174            } else if let Some(selected_text) = selected_text {
13175                self.select_next_state = Some(SelectNextState {
13176                    query: AhoCorasick::new(&[selected_text])?,
13177                    wordwise: false,
13178                    done: false,
13179                });
13180                self.select_next_match_internal(
13181                    display_map,
13182                    replace_newest,
13183                    autoscroll,
13184                    window,
13185                    cx,
13186                )?;
13187            }
13188        }
13189        Ok(())
13190    }
13191
13192    pub fn select_all_matches(
13193        &mut self,
13194        _action: &SelectAllMatches,
13195        window: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) -> Result<()> {
13198        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13199
13200        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13201
13202        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13203        let Some(select_next_state) = self.select_next_state.as_mut() else {
13204            return Ok(());
13205        };
13206        if select_next_state.done {
13207            return Ok(());
13208        }
13209
13210        let mut new_selections = Vec::new();
13211
13212        let reversed = self.selections.oldest::<usize>(cx).reversed;
13213        let buffer = &display_map.buffer_snapshot;
13214        let query_matches = select_next_state
13215            .query
13216            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13217
13218        for query_match in query_matches.into_iter() {
13219            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13220            let offset_range = if reversed {
13221                query_match.end()..query_match.start()
13222            } else {
13223                query_match.start()..query_match.end()
13224            };
13225            let display_range = offset_range.start.to_display_point(&display_map)
13226                ..offset_range.end.to_display_point(&display_map);
13227
13228            if !select_next_state.wordwise
13229                || (!movement::is_inside_word(&display_map, display_range.start)
13230                    && !movement::is_inside_word(&display_map, display_range.end))
13231            {
13232                new_selections.push(offset_range.start..offset_range.end);
13233            }
13234        }
13235
13236        select_next_state.done = true;
13237        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13238        self.change_selections(None, window, cx, |selections| {
13239            selections.select_ranges(new_selections)
13240        });
13241
13242        Ok(())
13243    }
13244
13245    pub fn select_next(
13246        &mut self,
13247        action: &SelectNext,
13248        window: &mut Window,
13249        cx: &mut Context<Self>,
13250    ) -> Result<()> {
13251        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13252        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13253        self.select_next_match_internal(
13254            &display_map,
13255            action.replace_newest,
13256            Some(Autoscroll::newest()),
13257            window,
13258            cx,
13259        )?;
13260        Ok(())
13261    }
13262
13263    pub fn select_previous(
13264        &mut self,
13265        action: &SelectPrevious,
13266        window: &mut Window,
13267        cx: &mut Context<Self>,
13268    ) -> Result<()> {
13269        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13271        let buffer = &display_map.buffer_snapshot;
13272        let mut selections = self.selections.all::<usize>(cx);
13273        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13274            let query = &select_prev_state.query;
13275            if !select_prev_state.done {
13276                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13277                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13278                let mut next_selected_range = None;
13279                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13280                let bytes_before_last_selection =
13281                    buffer.reversed_bytes_in_range(0..last_selection.start);
13282                let bytes_after_first_selection =
13283                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13284                let query_matches = query
13285                    .stream_find_iter(bytes_before_last_selection)
13286                    .map(|result| (last_selection.start, result))
13287                    .chain(
13288                        query
13289                            .stream_find_iter(bytes_after_first_selection)
13290                            .map(|result| (buffer.len(), result)),
13291                    );
13292                for (end_offset, query_match) in query_matches {
13293                    let query_match = query_match.unwrap(); // can only fail due to I/O
13294                    let offset_range =
13295                        end_offset - query_match.end()..end_offset - query_match.start();
13296                    let display_range = offset_range.start.to_display_point(&display_map)
13297                        ..offset_range.end.to_display_point(&display_map);
13298
13299                    if !select_prev_state.wordwise
13300                        || (!movement::is_inside_word(&display_map, display_range.start)
13301                            && !movement::is_inside_word(&display_map, display_range.end))
13302                    {
13303                        next_selected_range = Some(offset_range);
13304                        break;
13305                    }
13306                }
13307
13308                if let Some(next_selected_range) = next_selected_range {
13309                    self.select_match_ranges(
13310                        next_selected_range,
13311                        last_selection.reversed,
13312                        action.replace_newest,
13313                        Some(Autoscroll::newest()),
13314                        window,
13315                        cx,
13316                    );
13317                } else {
13318                    select_prev_state.done = true;
13319                }
13320            }
13321
13322            self.select_prev_state = Some(select_prev_state);
13323        } else {
13324            let mut only_carets = true;
13325            let mut same_text_selected = true;
13326            let mut selected_text = None;
13327
13328            let mut selections_iter = selections.iter().peekable();
13329            while let Some(selection) = selections_iter.next() {
13330                if selection.start != selection.end {
13331                    only_carets = false;
13332                }
13333
13334                if same_text_selected {
13335                    if selected_text.is_none() {
13336                        selected_text =
13337                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13338                    }
13339
13340                    if let Some(next_selection) = selections_iter.peek() {
13341                        if next_selection.range().len() == selection.range().len() {
13342                            let next_selected_text = buffer
13343                                .text_for_range(next_selection.range())
13344                                .collect::<String>();
13345                            if Some(next_selected_text) != selected_text {
13346                                same_text_selected = false;
13347                                selected_text = None;
13348                            }
13349                        } else {
13350                            same_text_selected = false;
13351                            selected_text = None;
13352                        }
13353                    }
13354                }
13355            }
13356
13357            if only_carets {
13358                for selection in &mut selections {
13359                    let word_range = movement::surrounding_word(
13360                        &display_map,
13361                        selection.start.to_display_point(&display_map),
13362                    );
13363                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13364                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13365                    selection.goal = SelectionGoal::None;
13366                    selection.reversed = false;
13367                    self.select_match_ranges(
13368                        selection.start..selection.end,
13369                        selection.reversed,
13370                        action.replace_newest,
13371                        Some(Autoscroll::newest()),
13372                        window,
13373                        cx,
13374                    );
13375                }
13376                if selections.len() == 1 {
13377                    let selection = selections
13378                        .last()
13379                        .expect("ensured that there's only one selection");
13380                    let query = buffer
13381                        .text_for_range(selection.start..selection.end)
13382                        .collect::<String>();
13383                    let is_empty = query.is_empty();
13384                    let select_state = SelectNextState {
13385                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13386                        wordwise: true,
13387                        done: is_empty,
13388                    };
13389                    self.select_prev_state = Some(select_state);
13390                } else {
13391                    self.select_prev_state = None;
13392                }
13393            } else if let Some(selected_text) = selected_text {
13394                self.select_prev_state = Some(SelectNextState {
13395                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13396                    wordwise: false,
13397                    done: false,
13398                });
13399                self.select_previous(action, window, cx)?;
13400            }
13401        }
13402        Ok(())
13403    }
13404
13405    pub fn find_next_match(
13406        &mut self,
13407        _: &FindNextMatch,
13408        window: &mut Window,
13409        cx: &mut Context<Self>,
13410    ) -> Result<()> {
13411        let selections = self.selections.disjoint_anchors();
13412        match selections.first() {
13413            Some(first) if selections.len() >= 2 => {
13414                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13415                    s.select_ranges([first.range()]);
13416                });
13417            }
13418            _ => self.select_next(
13419                &SelectNext {
13420                    replace_newest: true,
13421                },
13422                window,
13423                cx,
13424            )?,
13425        }
13426        Ok(())
13427    }
13428
13429    pub fn find_previous_match(
13430        &mut self,
13431        _: &FindPreviousMatch,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) -> Result<()> {
13435        let selections = self.selections.disjoint_anchors();
13436        match selections.last() {
13437            Some(last) if selections.len() >= 2 => {
13438                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13439                    s.select_ranges([last.range()]);
13440                });
13441            }
13442            _ => self.select_previous(
13443                &SelectPrevious {
13444                    replace_newest: true,
13445                },
13446                window,
13447                cx,
13448            )?,
13449        }
13450        Ok(())
13451    }
13452
13453    pub fn toggle_comments(
13454        &mut self,
13455        action: &ToggleComments,
13456        window: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        if self.read_only(cx) {
13460            return;
13461        }
13462        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13463        let text_layout_details = &self.text_layout_details(window);
13464        self.transact(window, cx, |this, window, cx| {
13465            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13466            let mut edits = Vec::new();
13467            let mut selection_edit_ranges = Vec::new();
13468            let mut last_toggled_row = None;
13469            let snapshot = this.buffer.read(cx).read(cx);
13470            let empty_str: Arc<str> = Arc::default();
13471            let mut suffixes_inserted = Vec::new();
13472            let ignore_indent = action.ignore_indent;
13473
13474            fn comment_prefix_range(
13475                snapshot: &MultiBufferSnapshot,
13476                row: MultiBufferRow,
13477                comment_prefix: &str,
13478                comment_prefix_whitespace: &str,
13479                ignore_indent: bool,
13480            ) -> Range<Point> {
13481                let indent_size = if ignore_indent {
13482                    0
13483                } else {
13484                    snapshot.indent_size_for_line(row).len
13485                };
13486
13487                let start = Point::new(row.0, indent_size);
13488
13489                let mut line_bytes = snapshot
13490                    .bytes_in_range(start..snapshot.max_point())
13491                    .flatten()
13492                    .copied();
13493
13494                // If this line currently begins with the line comment prefix, then record
13495                // the range containing the prefix.
13496                if line_bytes
13497                    .by_ref()
13498                    .take(comment_prefix.len())
13499                    .eq(comment_prefix.bytes())
13500                {
13501                    // Include any whitespace that matches the comment prefix.
13502                    let matching_whitespace_len = line_bytes
13503                        .zip(comment_prefix_whitespace.bytes())
13504                        .take_while(|(a, b)| a == b)
13505                        .count() as u32;
13506                    let end = Point::new(
13507                        start.row,
13508                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13509                    );
13510                    start..end
13511                } else {
13512                    start..start
13513                }
13514            }
13515
13516            fn comment_suffix_range(
13517                snapshot: &MultiBufferSnapshot,
13518                row: MultiBufferRow,
13519                comment_suffix: &str,
13520                comment_suffix_has_leading_space: bool,
13521            ) -> Range<Point> {
13522                let end = Point::new(row.0, snapshot.line_len(row));
13523                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13524
13525                let mut line_end_bytes = snapshot
13526                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13527                    .flatten()
13528                    .copied();
13529
13530                let leading_space_len = if suffix_start_column > 0
13531                    && line_end_bytes.next() == Some(b' ')
13532                    && comment_suffix_has_leading_space
13533                {
13534                    1
13535                } else {
13536                    0
13537                };
13538
13539                // If this line currently begins with the line comment prefix, then record
13540                // the range containing the prefix.
13541                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13542                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13543                    start..end
13544                } else {
13545                    end..end
13546                }
13547            }
13548
13549            // TODO: Handle selections that cross excerpts
13550            for selection in &mut selections {
13551                let start_column = snapshot
13552                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13553                    .len;
13554                let language = if let Some(language) =
13555                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13556                {
13557                    language
13558                } else {
13559                    continue;
13560                };
13561
13562                selection_edit_ranges.clear();
13563
13564                // If multiple selections contain a given row, avoid processing that
13565                // row more than once.
13566                let mut start_row = MultiBufferRow(selection.start.row);
13567                if last_toggled_row == Some(start_row) {
13568                    start_row = start_row.next_row();
13569                }
13570                let end_row =
13571                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13572                        MultiBufferRow(selection.end.row - 1)
13573                    } else {
13574                        MultiBufferRow(selection.end.row)
13575                    };
13576                last_toggled_row = Some(end_row);
13577
13578                if start_row > end_row {
13579                    continue;
13580                }
13581
13582                // If the language has line comments, toggle those.
13583                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13584
13585                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13586                if ignore_indent {
13587                    full_comment_prefixes = full_comment_prefixes
13588                        .into_iter()
13589                        .map(|s| Arc::from(s.trim_end()))
13590                        .collect();
13591                }
13592
13593                if !full_comment_prefixes.is_empty() {
13594                    let first_prefix = full_comment_prefixes
13595                        .first()
13596                        .expect("prefixes is non-empty");
13597                    let prefix_trimmed_lengths = full_comment_prefixes
13598                        .iter()
13599                        .map(|p| p.trim_end_matches(' ').len())
13600                        .collect::<SmallVec<[usize; 4]>>();
13601
13602                    let mut all_selection_lines_are_comments = true;
13603
13604                    for row in start_row.0..=end_row.0 {
13605                        let row = MultiBufferRow(row);
13606                        if start_row < end_row && snapshot.is_line_blank(row) {
13607                            continue;
13608                        }
13609
13610                        let prefix_range = full_comment_prefixes
13611                            .iter()
13612                            .zip(prefix_trimmed_lengths.iter().copied())
13613                            .map(|(prefix, trimmed_prefix_len)| {
13614                                comment_prefix_range(
13615                                    snapshot.deref(),
13616                                    row,
13617                                    &prefix[..trimmed_prefix_len],
13618                                    &prefix[trimmed_prefix_len..],
13619                                    ignore_indent,
13620                                )
13621                            })
13622                            .max_by_key(|range| range.end.column - range.start.column)
13623                            .expect("prefixes is non-empty");
13624
13625                        if prefix_range.is_empty() {
13626                            all_selection_lines_are_comments = false;
13627                        }
13628
13629                        selection_edit_ranges.push(prefix_range);
13630                    }
13631
13632                    if all_selection_lines_are_comments {
13633                        edits.extend(
13634                            selection_edit_ranges
13635                                .iter()
13636                                .cloned()
13637                                .map(|range| (range, empty_str.clone())),
13638                        );
13639                    } else {
13640                        let min_column = selection_edit_ranges
13641                            .iter()
13642                            .map(|range| range.start.column)
13643                            .min()
13644                            .unwrap_or(0);
13645                        edits.extend(selection_edit_ranges.iter().map(|range| {
13646                            let position = Point::new(range.start.row, min_column);
13647                            (position..position, first_prefix.clone())
13648                        }));
13649                    }
13650                } else if let Some((full_comment_prefix, comment_suffix)) =
13651                    language.block_comment_delimiters()
13652                {
13653                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13654                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13655                    let prefix_range = comment_prefix_range(
13656                        snapshot.deref(),
13657                        start_row,
13658                        comment_prefix,
13659                        comment_prefix_whitespace,
13660                        ignore_indent,
13661                    );
13662                    let suffix_range = comment_suffix_range(
13663                        snapshot.deref(),
13664                        end_row,
13665                        comment_suffix.trim_start_matches(' '),
13666                        comment_suffix.starts_with(' '),
13667                    );
13668
13669                    if prefix_range.is_empty() || suffix_range.is_empty() {
13670                        edits.push((
13671                            prefix_range.start..prefix_range.start,
13672                            full_comment_prefix.clone(),
13673                        ));
13674                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13675                        suffixes_inserted.push((end_row, comment_suffix.len()));
13676                    } else {
13677                        edits.push((prefix_range, empty_str.clone()));
13678                        edits.push((suffix_range, empty_str.clone()));
13679                    }
13680                } else {
13681                    continue;
13682                }
13683            }
13684
13685            drop(snapshot);
13686            this.buffer.update(cx, |buffer, cx| {
13687                buffer.edit(edits, None, cx);
13688            });
13689
13690            // Adjust selections so that they end before any comment suffixes that
13691            // were inserted.
13692            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13693            let mut selections = this.selections.all::<Point>(cx);
13694            let snapshot = this.buffer.read(cx).read(cx);
13695            for selection in &mut selections {
13696                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13697                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13698                        Ordering::Less => {
13699                            suffixes_inserted.next();
13700                            continue;
13701                        }
13702                        Ordering::Greater => break,
13703                        Ordering::Equal => {
13704                            if selection.end.column == snapshot.line_len(row) {
13705                                if selection.is_empty() {
13706                                    selection.start.column -= suffix_len as u32;
13707                                }
13708                                selection.end.column -= suffix_len as u32;
13709                            }
13710                            break;
13711                        }
13712                    }
13713                }
13714            }
13715
13716            drop(snapshot);
13717            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13718                s.select(selections)
13719            });
13720
13721            let selections = this.selections.all::<Point>(cx);
13722            let selections_on_single_row = selections.windows(2).all(|selections| {
13723                selections[0].start.row == selections[1].start.row
13724                    && selections[0].end.row == selections[1].end.row
13725                    && selections[0].start.row == selections[0].end.row
13726            });
13727            let selections_selecting = selections
13728                .iter()
13729                .any(|selection| selection.start != selection.end);
13730            let advance_downwards = action.advance_downwards
13731                && selections_on_single_row
13732                && !selections_selecting
13733                && !matches!(this.mode, EditorMode::SingleLine { .. });
13734
13735            if advance_downwards {
13736                let snapshot = this.buffer.read(cx).snapshot(cx);
13737
13738                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13739                    s.move_cursors_with(|display_snapshot, display_point, _| {
13740                        let mut point = display_point.to_point(display_snapshot);
13741                        point.row += 1;
13742                        point = snapshot.clip_point(point, Bias::Left);
13743                        let display_point = point.to_display_point(display_snapshot);
13744                        let goal = SelectionGoal::HorizontalPosition(
13745                            display_snapshot
13746                                .x_for_display_point(display_point, text_layout_details)
13747                                .into(),
13748                        );
13749                        (display_point, goal)
13750                    })
13751                });
13752            }
13753        });
13754    }
13755
13756    pub fn select_enclosing_symbol(
13757        &mut self,
13758        _: &SelectEnclosingSymbol,
13759        window: &mut Window,
13760        cx: &mut Context<Self>,
13761    ) {
13762        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13763
13764        let buffer = self.buffer.read(cx).snapshot(cx);
13765        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13766
13767        fn update_selection(
13768            selection: &Selection<usize>,
13769            buffer_snap: &MultiBufferSnapshot,
13770        ) -> Option<Selection<usize>> {
13771            let cursor = selection.head();
13772            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13773            for symbol in symbols.iter().rev() {
13774                let start = symbol.range.start.to_offset(buffer_snap);
13775                let end = symbol.range.end.to_offset(buffer_snap);
13776                let new_range = start..end;
13777                if start < selection.start || end > selection.end {
13778                    return Some(Selection {
13779                        id: selection.id,
13780                        start: new_range.start,
13781                        end: new_range.end,
13782                        goal: SelectionGoal::None,
13783                        reversed: selection.reversed,
13784                    });
13785                }
13786            }
13787            None
13788        }
13789
13790        let mut selected_larger_symbol = false;
13791        let new_selections = old_selections
13792            .iter()
13793            .map(|selection| match update_selection(selection, &buffer) {
13794                Some(new_selection) => {
13795                    if new_selection.range() != selection.range() {
13796                        selected_larger_symbol = true;
13797                    }
13798                    new_selection
13799                }
13800                None => selection.clone(),
13801            })
13802            .collect::<Vec<_>>();
13803
13804        if selected_larger_symbol {
13805            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13806                s.select(new_selections);
13807            });
13808        }
13809    }
13810
13811    pub fn select_larger_syntax_node(
13812        &mut self,
13813        _: &SelectLargerSyntaxNode,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        let Some(visible_row_count) = self.visible_row_count() else {
13818            return;
13819        };
13820        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13821        if old_selections.is_empty() {
13822            return;
13823        }
13824
13825        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13826
13827        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13828        let buffer = self.buffer.read(cx).snapshot(cx);
13829
13830        let mut selected_larger_node = false;
13831        let mut new_selections = old_selections
13832            .iter()
13833            .map(|selection| {
13834                let old_range = selection.start..selection.end;
13835
13836                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13837                    // manually select word at selection
13838                    if ["string_content", "inline"].contains(&node.kind()) {
13839                        let word_range = {
13840                            let display_point = buffer
13841                                .offset_to_point(old_range.start)
13842                                .to_display_point(&display_map);
13843                            let Range { start, end } =
13844                                movement::surrounding_word(&display_map, display_point);
13845                            start.to_point(&display_map).to_offset(&buffer)
13846                                ..end.to_point(&display_map).to_offset(&buffer)
13847                        };
13848                        // ignore if word is already selected
13849                        if !word_range.is_empty() && old_range != word_range {
13850                            let last_word_range = {
13851                                let display_point = buffer
13852                                    .offset_to_point(old_range.end)
13853                                    .to_display_point(&display_map);
13854                                let Range { start, end } =
13855                                    movement::surrounding_word(&display_map, display_point);
13856                                start.to_point(&display_map).to_offset(&buffer)
13857                                    ..end.to_point(&display_map).to_offset(&buffer)
13858                            };
13859                            // only select word if start and end point belongs to same word
13860                            if word_range == last_word_range {
13861                                selected_larger_node = true;
13862                                return Selection {
13863                                    id: selection.id,
13864                                    start: word_range.start,
13865                                    end: word_range.end,
13866                                    goal: SelectionGoal::None,
13867                                    reversed: selection.reversed,
13868                                };
13869                            }
13870                        }
13871                    }
13872                }
13873
13874                let mut new_range = old_range.clone();
13875                while let Some((_node, containing_range)) =
13876                    buffer.syntax_ancestor(new_range.clone())
13877                {
13878                    new_range = match containing_range {
13879                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13880                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13881                    };
13882                    if !display_map.intersects_fold(new_range.start)
13883                        && !display_map.intersects_fold(new_range.end)
13884                    {
13885                        break;
13886                    }
13887                }
13888
13889                selected_larger_node |= new_range != old_range;
13890                Selection {
13891                    id: selection.id,
13892                    start: new_range.start,
13893                    end: new_range.end,
13894                    goal: SelectionGoal::None,
13895                    reversed: selection.reversed,
13896                }
13897            })
13898            .collect::<Vec<_>>();
13899
13900        if !selected_larger_node {
13901            return; // don't put this call in the history
13902        }
13903
13904        // scroll based on transformation done to the last selection created by the user
13905        let (last_old, last_new) = old_selections
13906            .last()
13907            .zip(new_selections.last().cloned())
13908            .expect("old_selections isn't empty");
13909
13910        // revert selection
13911        let is_selection_reversed = {
13912            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13913            new_selections.last_mut().expect("checked above").reversed =
13914                should_newest_selection_be_reversed;
13915            should_newest_selection_be_reversed
13916        };
13917
13918        if selected_larger_node {
13919            self.select_syntax_node_history.disable_clearing = true;
13920            self.change_selections(None, window, cx, |s| {
13921                s.select(new_selections.clone());
13922            });
13923            self.select_syntax_node_history.disable_clearing = false;
13924        }
13925
13926        let start_row = last_new.start.to_display_point(&display_map).row().0;
13927        let end_row = last_new.end.to_display_point(&display_map).row().0;
13928        let selection_height = end_row - start_row + 1;
13929        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13930
13931        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13932        let scroll_behavior = if fits_on_the_screen {
13933            self.request_autoscroll(Autoscroll::fit(), cx);
13934            SelectSyntaxNodeScrollBehavior::FitSelection
13935        } else if is_selection_reversed {
13936            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13937            SelectSyntaxNodeScrollBehavior::CursorTop
13938        } else {
13939            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13940            SelectSyntaxNodeScrollBehavior::CursorBottom
13941        };
13942
13943        self.select_syntax_node_history.push((
13944            old_selections,
13945            scroll_behavior,
13946            is_selection_reversed,
13947        ));
13948    }
13949
13950    pub fn select_smaller_syntax_node(
13951        &mut self,
13952        _: &SelectSmallerSyntaxNode,
13953        window: &mut Window,
13954        cx: &mut Context<Self>,
13955    ) {
13956        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13957
13958        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13959            self.select_syntax_node_history.pop()
13960        {
13961            if let Some(selection) = selections.last_mut() {
13962                selection.reversed = is_selection_reversed;
13963            }
13964
13965            self.select_syntax_node_history.disable_clearing = true;
13966            self.change_selections(None, window, cx, |s| {
13967                s.select(selections.to_vec());
13968            });
13969            self.select_syntax_node_history.disable_clearing = false;
13970
13971            match scroll_behavior {
13972                SelectSyntaxNodeScrollBehavior::CursorTop => {
13973                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13974                }
13975                SelectSyntaxNodeScrollBehavior::FitSelection => {
13976                    self.request_autoscroll(Autoscroll::fit(), cx);
13977                }
13978                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13979                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13980                }
13981            }
13982        }
13983    }
13984
13985    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13986        if !EditorSettings::get_global(cx).gutter.runnables {
13987            self.clear_tasks();
13988            return Task::ready(());
13989        }
13990        let project = self.project.as_ref().map(Entity::downgrade);
13991        let task_sources = self.lsp_task_sources(cx);
13992        let multi_buffer = self.buffer.downgrade();
13993        cx.spawn_in(window, async move |editor, cx| {
13994            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13995            let Some(project) = project.and_then(|p| p.upgrade()) else {
13996                return;
13997            };
13998            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13999                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14000            }) else {
14001                return;
14002            };
14003
14004            let hide_runnables = project
14005                .update(cx, |project, cx| {
14006                    // Do not display any test indicators in non-dev server remote projects.
14007                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14008                })
14009                .unwrap_or(true);
14010            if hide_runnables {
14011                return;
14012            }
14013            let new_rows =
14014                cx.background_spawn({
14015                    let snapshot = display_snapshot.clone();
14016                    async move {
14017                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14018                    }
14019                })
14020                    .await;
14021            let Ok(lsp_tasks) =
14022                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14023            else {
14024                return;
14025            };
14026            let lsp_tasks = lsp_tasks.await;
14027
14028            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14029                lsp_tasks
14030                    .into_iter()
14031                    .flat_map(|(kind, tasks)| {
14032                        tasks.into_iter().filter_map(move |(location, task)| {
14033                            Some((kind.clone(), location?, task))
14034                        })
14035                    })
14036                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14037                        let buffer = location.target.buffer;
14038                        let buffer_snapshot = buffer.read(cx).snapshot();
14039                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14040                            |(excerpt_id, snapshot, _)| {
14041                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14042                                    display_snapshot
14043                                        .buffer_snapshot
14044                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14045                                } else {
14046                                    None
14047                                }
14048                            },
14049                        );
14050                        if let Some(offset) = offset {
14051                            let task_buffer_range =
14052                                location.target.range.to_point(&buffer_snapshot);
14053                            let context_buffer_range =
14054                                task_buffer_range.to_offset(&buffer_snapshot);
14055                            let context_range = BufferOffset(context_buffer_range.start)
14056                                ..BufferOffset(context_buffer_range.end);
14057
14058                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14059                                .or_insert_with(|| RunnableTasks {
14060                                    templates: Vec::new(),
14061                                    offset,
14062                                    column: task_buffer_range.start.column,
14063                                    extra_variables: HashMap::default(),
14064                                    context_range,
14065                                })
14066                                .templates
14067                                .push((kind, task.original_task().clone()));
14068                        }
14069
14070                        acc
14071                    })
14072            }) else {
14073                return;
14074            };
14075
14076            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14077                buffer.language_settings(cx).tasks.prefer_lsp
14078            }) else {
14079                return;
14080            };
14081
14082            let rows = Self::runnable_rows(
14083                project,
14084                display_snapshot,
14085                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14086                new_rows,
14087                cx.clone(),
14088            )
14089            .await;
14090            editor
14091                .update(cx, |editor, _| {
14092                    editor.clear_tasks();
14093                    for (key, mut value) in rows {
14094                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14095                            value.templates.extend(lsp_tasks.templates);
14096                        }
14097
14098                        editor.insert_tasks(key, value);
14099                    }
14100                    for (key, value) in lsp_tasks_by_rows {
14101                        editor.insert_tasks(key, value);
14102                    }
14103                })
14104                .ok();
14105        })
14106    }
14107    fn fetch_runnable_ranges(
14108        snapshot: &DisplaySnapshot,
14109        range: Range<Anchor>,
14110    ) -> Vec<language::RunnableRange> {
14111        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14112    }
14113
14114    fn runnable_rows(
14115        project: Entity<Project>,
14116        snapshot: DisplaySnapshot,
14117        prefer_lsp: bool,
14118        runnable_ranges: Vec<RunnableRange>,
14119        cx: AsyncWindowContext,
14120    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14121        cx.spawn(async move |cx| {
14122            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14123            for mut runnable in runnable_ranges {
14124                let Some(tasks) = cx
14125                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14126                    .ok()
14127                else {
14128                    continue;
14129                };
14130                let mut tasks = tasks.await;
14131
14132                if prefer_lsp {
14133                    tasks.retain(|(task_kind, _)| {
14134                        !matches!(task_kind, TaskSourceKind::Language { .. })
14135                    });
14136                }
14137                if tasks.is_empty() {
14138                    continue;
14139                }
14140
14141                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14142                let Some(row) = snapshot
14143                    .buffer_snapshot
14144                    .buffer_line_for_row(MultiBufferRow(point.row))
14145                    .map(|(_, range)| range.start.row)
14146                else {
14147                    continue;
14148                };
14149
14150                let context_range =
14151                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14152                runnable_rows.push((
14153                    (runnable.buffer_id, row),
14154                    RunnableTasks {
14155                        templates: tasks,
14156                        offset: snapshot
14157                            .buffer_snapshot
14158                            .anchor_before(runnable.run_range.start),
14159                        context_range,
14160                        column: point.column,
14161                        extra_variables: runnable.extra_captures,
14162                    },
14163                ));
14164            }
14165            runnable_rows
14166        })
14167    }
14168
14169    fn templates_with_tags(
14170        project: &Entity<Project>,
14171        runnable: &mut Runnable,
14172        cx: &mut App,
14173    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14174        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14175            let (worktree_id, file) = project
14176                .buffer_for_id(runnable.buffer, cx)
14177                .and_then(|buffer| buffer.read(cx).file())
14178                .map(|file| (file.worktree_id(cx), file.clone()))
14179                .unzip();
14180
14181            (
14182                project.task_store().read(cx).task_inventory().cloned(),
14183                worktree_id,
14184                file,
14185            )
14186        });
14187
14188        let tags = mem::take(&mut runnable.tags);
14189        let language = runnable.language.clone();
14190        cx.spawn(async move |cx| {
14191            let mut templates_with_tags = Vec::new();
14192            if let Some(inventory) = inventory {
14193                for RunnableTag(tag) in tags {
14194                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14195                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14196                    }) else {
14197                        return templates_with_tags;
14198                    };
14199                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14200                        move |(_, template)| {
14201                            template.tags.iter().any(|source_tag| source_tag == &tag)
14202                        },
14203                    ));
14204                }
14205            }
14206            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14207
14208            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14209                // Strongest source wins; if we have worktree tag binding, prefer that to
14210                // global and language bindings;
14211                // if we have a global binding, prefer that to language binding.
14212                let first_mismatch = templates_with_tags
14213                    .iter()
14214                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14215                if let Some(index) = first_mismatch {
14216                    templates_with_tags.truncate(index);
14217                }
14218            }
14219
14220            templates_with_tags
14221        })
14222    }
14223
14224    pub fn move_to_enclosing_bracket(
14225        &mut self,
14226        _: &MoveToEnclosingBracket,
14227        window: &mut Window,
14228        cx: &mut Context<Self>,
14229    ) {
14230        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14231        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14232            s.move_offsets_with(|snapshot, selection| {
14233                let Some(enclosing_bracket_ranges) =
14234                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14235                else {
14236                    return;
14237                };
14238
14239                let mut best_length = usize::MAX;
14240                let mut best_inside = false;
14241                let mut best_in_bracket_range = false;
14242                let mut best_destination = None;
14243                for (open, close) in enclosing_bracket_ranges {
14244                    let close = close.to_inclusive();
14245                    let length = close.end() - open.start;
14246                    let inside = selection.start >= open.end && selection.end <= *close.start();
14247                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14248                        || close.contains(&selection.head());
14249
14250                    // If best is next to a bracket and current isn't, skip
14251                    if !in_bracket_range && best_in_bracket_range {
14252                        continue;
14253                    }
14254
14255                    // Prefer smaller lengths unless best is inside and current isn't
14256                    if length > best_length && (best_inside || !inside) {
14257                        continue;
14258                    }
14259
14260                    best_length = length;
14261                    best_inside = inside;
14262                    best_in_bracket_range = in_bracket_range;
14263                    best_destination = Some(
14264                        if close.contains(&selection.start) && close.contains(&selection.end) {
14265                            if inside { open.end } else { open.start }
14266                        } else if inside {
14267                            *close.start()
14268                        } else {
14269                            *close.end()
14270                        },
14271                    );
14272                }
14273
14274                if let Some(destination) = best_destination {
14275                    selection.collapse_to(destination, SelectionGoal::None);
14276                }
14277            })
14278        });
14279    }
14280
14281    pub fn undo_selection(
14282        &mut self,
14283        _: &UndoSelection,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) {
14287        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14288        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14289            self.selection_history.mode = SelectionHistoryMode::Undoing;
14290            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14291                this.end_selection(window, cx);
14292                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14293                    s.select_anchors(entry.selections.to_vec())
14294                });
14295            });
14296            self.selection_history.mode = SelectionHistoryMode::Normal;
14297
14298            self.select_next_state = entry.select_next_state;
14299            self.select_prev_state = entry.select_prev_state;
14300            self.add_selections_state = entry.add_selections_state;
14301        }
14302    }
14303
14304    pub fn redo_selection(
14305        &mut self,
14306        _: &RedoSelection,
14307        window: &mut Window,
14308        cx: &mut Context<Self>,
14309    ) {
14310        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14311        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14312            self.selection_history.mode = SelectionHistoryMode::Redoing;
14313            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14314                this.end_selection(window, cx);
14315                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14316                    s.select_anchors(entry.selections.to_vec())
14317                });
14318            });
14319            self.selection_history.mode = SelectionHistoryMode::Normal;
14320
14321            self.select_next_state = entry.select_next_state;
14322            self.select_prev_state = entry.select_prev_state;
14323            self.add_selections_state = entry.add_selections_state;
14324        }
14325    }
14326
14327    pub fn expand_excerpts(
14328        &mut self,
14329        action: &ExpandExcerpts,
14330        _: &mut Window,
14331        cx: &mut Context<Self>,
14332    ) {
14333        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14334    }
14335
14336    pub fn expand_excerpts_down(
14337        &mut self,
14338        action: &ExpandExcerptsDown,
14339        _: &mut Window,
14340        cx: &mut Context<Self>,
14341    ) {
14342        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14343    }
14344
14345    pub fn expand_excerpts_up(
14346        &mut self,
14347        action: &ExpandExcerptsUp,
14348        _: &mut Window,
14349        cx: &mut Context<Self>,
14350    ) {
14351        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14352    }
14353
14354    pub fn expand_excerpts_for_direction(
14355        &mut self,
14356        lines: u32,
14357        direction: ExpandExcerptDirection,
14358
14359        cx: &mut Context<Self>,
14360    ) {
14361        let selections = self.selections.disjoint_anchors();
14362
14363        let lines = if lines == 0 {
14364            EditorSettings::get_global(cx).expand_excerpt_lines
14365        } else {
14366            lines
14367        };
14368
14369        self.buffer.update(cx, |buffer, cx| {
14370            let snapshot = buffer.snapshot(cx);
14371            let mut excerpt_ids = selections
14372                .iter()
14373                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14374                .collect::<Vec<_>>();
14375            excerpt_ids.sort();
14376            excerpt_ids.dedup();
14377            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14378        })
14379    }
14380
14381    pub fn expand_excerpt(
14382        &mut self,
14383        excerpt: ExcerptId,
14384        direction: ExpandExcerptDirection,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) {
14388        let current_scroll_position = self.scroll_position(cx);
14389        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14390        let mut should_scroll_up = false;
14391
14392        if direction == ExpandExcerptDirection::Down {
14393            let multi_buffer = self.buffer.read(cx);
14394            let snapshot = multi_buffer.snapshot(cx);
14395            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14396                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14397                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14398                        let buffer_snapshot = buffer.read(cx).snapshot();
14399                        let excerpt_end_row =
14400                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14401                        let last_row = buffer_snapshot.max_point().row;
14402                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14403                        should_scroll_up = lines_below >= lines_to_expand;
14404                    }
14405                }
14406            }
14407        }
14408
14409        self.buffer.update(cx, |buffer, cx| {
14410            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14411        });
14412
14413        if should_scroll_up {
14414            let new_scroll_position =
14415                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14416            self.set_scroll_position(new_scroll_position, window, cx);
14417        }
14418    }
14419
14420    pub fn go_to_singleton_buffer_point(
14421        &mut self,
14422        point: Point,
14423        window: &mut Window,
14424        cx: &mut Context<Self>,
14425    ) {
14426        self.go_to_singleton_buffer_range(point..point, window, cx);
14427    }
14428
14429    pub fn go_to_singleton_buffer_range(
14430        &mut self,
14431        range: Range<Point>,
14432        window: &mut Window,
14433        cx: &mut Context<Self>,
14434    ) {
14435        let multibuffer = self.buffer().read(cx);
14436        let Some(buffer) = multibuffer.as_singleton() else {
14437            return;
14438        };
14439        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14440            return;
14441        };
14442        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14443            return;
14444        };
14445        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14446            s.select_anchor_ranges([start..end])
14447        });
14448    }
14449
14450    pub fn go_to_diagnostic(
14451        &mut self,
14452        _: &GoToDiagnostic,
14453        window: &mut Window,
14454        cx: &mut Context<Self>,
14455    ) {
14456        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14457        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14458    }
14459
14460    pub fn go_to_prev_diagnostic(
14461        &mut self,
14462        _: &GoToPreviousDiagnostic,
14463        window: &mut Window,
14464        cx: &mut Context<Self>,
14465    ) {
14466        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14467        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14468    }
14469
14470    pub fn go_to_diagnostic_impl(
14471        &mut self,
14472        direction: Direction,
14473        window: &mut Window,
14474        cx: &mut Context<Self>,
14475    ) {
14476        let buffer = self.buffer.read(cx).snapshot(cx);
14477        let selection = self.selections.newest::<usize>(cx);
14478
14479        let mut active_group_id = None;
14480        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14481            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14482                active_group_id = Some(active_group.group_id);
14483            }
14484        }
14485
14486        fn filtered(
14487            snapshot: EditorSnapshot,
14488            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14489        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14490            diagnostics
14491                .filter(|entry| entry.range.start != entry.range.end)
14492                .filter(|entry| !entry.diagnostic.is_unnecessary)
14493                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14494        }
14495
14496        let snapshot = self.snapshot(window, cx);
14497        let before = filtered(
14498            snapshot.clone(),
14499            buffer
14500                .diagnostics_in_range(0..selection.start)
14501                .filter(|entry| entry.range.start <= selection.start),
14502        );
14503        let after = filtered(
14504            snapshot,
14505            buffer
14506                .diagnostics_in_range(selection.start..buffer.len())
14507                .filter(|entry| entry.range.start >= selection.start),
14508        );
14509
14510        let mut found: Option<DiagnosticEntry<usize>> = None;
14511        if direction == Direction::Prev {
14512            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14513            {
14514                for diagnostic in prev_diagnostics.into_iter().rev() {
14515                    if diagnostic.range.start != selection.start
14516                        || active_group_id
14517                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14518                    {
14519                        found = Some(diagnostic);
14520                        break 'outer;
14521                    }
14522                }
14523            }
14524        } else {
14525            for diagnostic in after.chain(before) {
14526                if diagnostic.range.start != selection.start
14527                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14528                {
14529                    found = Some(diagnostic);
14530                    break;
14531                }
14532            }
14533        }
14534        let Some(next_diagnostic) = found else {
14535            return;
14536        };
14537
14538        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14539            return;
14540        };
14541        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14542            s.select_ranges(vec![
14543                next_diagnostic.range.start..next_diagnostic.range.start,
14544            ])
14545        });
14546        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14547        self.refresh_inline_completion(false, true, window, cx);
14548    }
14549
14550    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14551        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14552        let snapshot = self.snapshot(window, cx);
14553        let selection = self.selections.newest::<Point>(cx);
14554        self.go_to_hunk_before_or_after_position(
14555            &snapshot,
14556            selection.head(),
14557            Direction::Next,
14558            window,
14559            cx,
14560        );
14561    }
14562
14563    pub fn go_to_hunk_before_or_after_position(
14564        &mut self,
14565        snapshot: &EditorSnapshot,
14566        position: Point,
14567        direction: Direction,
14568        window: &mut Window,
14569        cx: &mut Context<Editor>,
14570    ) {
14571        let row = if direction == Direction::Next {
14572            self.hunk_after_position(snapshot, position)
14573                .map(|hunk| hunk.row_range.start)
14574        } else {
14575            self.hunk_before_position(snapshot, position)
14576        };
14577
14578        if let Some(row) = row {
14579            let destination = Point::new(row.0, 0);
14580            let autoscroll = Autoscroll::center();
14581
14582            self.unfold_ranges(&[destination..destination], false, false, cx);
14583            self.change_selections(Some(autoscroll), window, cx, |s| {
14584                s.select_ranges([destination..destination]);
14585            });
14586        }
14587    }
14588
14589    fn hunk_after_position(
14590        &mut self,
14591        snapshot: &EditorSnapshot,
14592        position: Point,
14593    ) -> Option<MultiBufferDiffHunk> {
14594        snapshot
14595            .buffer_snapshot
14596            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14597            .find(|hunk| hunk.row_range.start.0 > position.row)
14598            .or_else(|| {
14599                snapshot
14600                    .buffer_snapshot
14601                    .diff_hunks_in_range(Point::zero()..position)
14602                    .find(|hunk| hunk.row_range.end.0 < position.row)
14603            })
14604    }
14605
14606    fn go_to_prev_hunk(
14607        &mut self,
14608        _: &GoToPreviousHunk,
14609        window: &mut Window,
14610        cx: &mut Context<Self>,
14611    ) {
14612        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14613        let snapshot = self.snapshot(window, cx);
14614        let selection = self.selections.newest::<Point>(cx);
14615        self.go_to_hunk_before_or_after_position(
14616            &snapshot,
14617            selection.head(),
14618            Direction::Prev,
14619            window,
14620            cx,
14621        );
14622    }
14623
14624    fn hunk_before_position(
14625        &mut self,
14626        snapshot: &EditorSnapshot,
14627        position: Point,
14628    ) -> Option<MultiBufferRow> {
14629        snapshot
14630            .buffer_snapshot
14631            .diff_hunk_before(position)
14632            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14633    }
14634
14635    fn go_to_next_change(
14636        &mut self,
14637        _: &GoToNextChange,
14638        window: &mut Window,
14639        cx: &mut Context<Self>,
14640    ) {
14641        if let Some(selections) = self
14642            .change_list
14643            .next_change(1, Direction::Next)
14644            .map(|s| s.to_vec())
14645        {
14646            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14647                let map = s.display_map();
14648                s.select_display_ranges(selections.iter().map(|a| {
14649                    let point = a.to_display_point(&map);
14650                    point..point
14651                }))
14652            })
14653        }
14654    }
14655
14656    fn go_to_previous_change(
14657        &mut self,
14658        _: &GoToPreviousChange,
14659        window: &mut Window,
14660        cx: &mut Context<Self>,
14661    ) {
14662        if let Some(selections) = self
14663            .change_list
14664            .next_change(1, Direction::Prev)
14665            .map(|s| s.to_vec())
14666        {
14667            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14668                let map = s.display_map();
14669                s.select_display_ranges(selections.iter().map(|a| {
14670                    let point = a.to_display_point(&map);
14671                    point..point
14672                }))
14673            })
14674        }
14675    }
14676
14677    fn go_to_line<T: 'static>(
14678        &mut self,
14679        position: Anchor,
14680        highlight_color: Option<Hsla>,
14681        window: &mut Window,
14682        cx: &mut Context<Self>,
14683    ) {
14684        let snapshot = self.snapshot(window, cx).display_snapshot;
14685        let position = position.to_point(&snapshot.buffer_snapshot);
14686        let start = snapshot
14687            .buffer_snapshot
14688            .clip_point(Point::new(position.row, 0), Bias::Left);
14689        let end = start + Point::new(1, 0);
14690        let start = snapshot.buffer_snapshot.anchor_before(start);
14691        let end = snapshot.buffer_snapshot.anchor_before(end);
14692
14693        self.highlight_rows::<T>(
14694            start..end,
14695            highlight_color
14696                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14697            Default::default(),
14698            cx,
14699        );
14700
14701        if self.buffer.read(cx).is_singleton() {
14702            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14703        }
14704    }
14705
14706    pub fn go_to_definition(
14707        &mut self,
14708        _: &GoToDefinition,
14709        window: &mut Window,
14710        cx: &mut Context<Self>,
14711    ) -> Task<Result<Navigated>> {
14712        let definition =
14713            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14714        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14715        cx.spawn_in(window, async move |editor, cx| {
14716            if definition.await? == Navigated::Yes {
14717                return Ok(Navigated::Yes);
14718            }
14719            match fallback_strategy {
14720                GoToDefinitionFallback::None => Ok(Navigated::No),
14721                GoToDefinitionFallback::FindAllReferences => {
14722                    match editor.update_in(cx, |editor, window, cx| {
14723                        editor.find_all_references(&FindAllReferences, window, cx)
14724                    })? {
14725                        Some(references) => references.await,
14726                        None => Ok(Navigated::No),
14727                    }
14728                }
14729            }
14730        })
14731    }
14732
14733    pub fn go_to_declaration(
14734        &mut self,
14735        _: &GoToDeclaration,
14736        window: &mut Window,
14737        cx: &mut Context<Self>,
14738    ) -> Task<Result<Navigated>> {
14739        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14740    }
14741
14742    pub fn go_to_declaration_split(
14743        &mut self,
14744        _: &GoToDeclaration,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) -> Task<Result<Navigated>> {
14748        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14749    }
14750
14751    pub fn go_to_implementation(
14752        &mut self,
14753        _: &GoToImplementation,
14754        window: &mut Window,
14755        cx: &mut Context<Self>,
14756    ) -> Task<Result<Navigated>> {
14757        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14758    }
14759
14760    pub fn go_to_implementation_split(
14761        &mut self,
14762        _: &GoToImplementationSplit,
14763        window: &mut Window,
14764        cx: &mut Context<Self>,
14765    ) -> Task<Result<Navigated>> {
14766        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14767    }
14768
14769    pub fn go_to_type_definition(
14770        &mut self,
14771        _: &GoToTypeDefinition,
14772        window: &mut Window,
14773        cx: &mut Context<Self>,
14774    ) -> Task<Result<Navigated>> {
14775        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14776    }
14777
14778    pub fn go_to_definition_split(
14779        &mut self,
14780        _: &GoToDefinitionSplit,
14781        window: &mut Window,
14782        cx: &mut Context<Self>,
14783    ) -> Task<Result<Navigated>> {
14784        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14785    }
14786
14787    pub fn go_to_type_definition_split(
14788        &mut self,
14789        _: &GoToTypeDefinitionSplit,
14790        window: &mut Window,
14791        cx: &mut Context<Self>,
14792    ) -> Task<Result<Navigated>> {
14793        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14794    }
14795
14796    fn go_to_definition_of_kind(
14797        &mut self,
14798        kind: GotoDefinitionKind,
14799        split: bool,
14800        window: &mut Window,
14801        cx: &mut Context<Self>,
14802    ) -> Task<Result<Navigated>> {
14803        let Some(provider) = self.semantics_provider.clone() else {
14804            return Task::ready(Ok(Navigated::No));
14805        };
14806        let head = self.selections.newest::<usize>(cx).head();
14807        let buffer = self.buffer.read(cx);
14808        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14809            text_anchor
14810        } else {
14811            return Task::ready(Ok(Navigated::No));
14812        };
14813
14814        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14815            return Task::ready(Ok(Navigated::No));
14816        };
14817
14818        cx.spawn_in(window, async move |editor, cx| {
14819            let definitions = definitions.await?;
14820            let navigated = editor
14821                .update_in(cx, |editor, window, cx| {
14822                    editor.navigate_to_hover_links(
14823                        Some(kind),
14824                        definitions
14825                            .into_iter()
14826                            .filter(|location| {
14827                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14828                            })
14829                            .map(HoverLink::Text)
14830                            .collect::<Vec<_>>(),
14831                        split,
14832                        window,
14833                        cx,
14834                    )
14835                })?
14836                .await?;
14837            anyhow::Ok(navigated)
14838        })
14839    }
14840
14841    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14842        let selection = self.selections.newest_anchor();
14843        let head = selection.head();
14844        let tail = selection.tail();
14845
14846        let Some((buffer, start_position)) =
14847            self.buffer.read(cx).text_anchor_for_position(head, cx)
14848        else {
14849            return;
14850        };
14851
14852        let end_position = if head != tail {
14853            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14854                return;
14855            };
14856            Some(pos)
14857        } else {
14858            None
14859        };
14860
14861        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14862            let url = if let Some(end_pos) = end_position {
14863                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14864            } else {
14865                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14866            };
14867
14868            if let Some(url) = url {
14869                editor.update(cx, |_, cx| {
14870                    cx.open_url(&url);
14871                })
14872            } else {
14873                Ok(())
14874            }
14875        });
14876
14877        url_finder.detach();
14878    }
14879
14880    pub fn open_selected_filename(
14881        &mut self,
14882        _: &OpenSelectedFilename,
14883        window: &mut Window,
14884        cx: &mut Context<Self>,
14885    ) {
14886        let Some(workspace) = self.workspace() else {
14887            return;
14888        };
14889
14890        let position = self.selections.newest_anchor().head();
14891
14892        let Some((buffer, buffer_position)) =
14893            self.buffer.read(cx).text_anchor_for_position(position, cx)
14894        else {
14895            return;
14896        };
14897
14898        let project = self.project.clone();
14899
14900        cx.spawn_in(window, async move |_, cx| {
14901            let result = find_file(&buffer, project, buffer_position, cx).await;
14902
14903            if let Some((_, path)) = result {
14904                workspace
14905                    .update_in(cx, |workspace, window, cx| {
14906                        workspace.open_resolved_path(path, window, cx)
14907                    })?
14908                    .await?;
14909            }
14910            anyhow::Ok(())
14911        })
14912        .detach();
14913    }
14914
14915    pub(crate) fn navigate_to_hover_links(
14916        &mut self,
14917        kind: Option<GotoDefinitionKind>,
14918        mut definitions: Vec<HoverLink>,
14919        split: bool,
14920        window: &mut Window,
14921        cx: &mut Context<Editor>,
14922    ) -> Task<Result<Navigated>> {
14923        // If there is one definition, just open it directly
14924        if definitions.len() == 1 {
14925            let definition = definitions.pop().unwrap();
14926
14927            enum TargetTaskResult {
14928                Location(Option<Location>),
14929                AlreadyNavigated,
14930            }
14931
14932            let target_task = match definition {
14933                HoverLink::Text(link) => {
14934                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14935                }
14936                HoverLink::InlayHint(lsp_location, server_id) => {
14937                    let computation =
14938                        self.compute_target_location(lsp_location, server_id, window, cx);
14939                    cx.background_spawn(async move {
14940                        let location = computation.await?;
14941                        Ok(TargetTaskResult::Location(location))
14942                    })
14943                }
14944                HoverLink::Url(url) => {
14945                    cx.open_url(&url);
14946                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14947                }
14948                HoverLink::File(path) => {
14949                    if let Some(workspace) = self.workspace() {
14950                        cx.spawn_in(window, async move |_, cx| {
14951                            workspace
14952                                .update_in(cx, |workspace, window, cx| {
14953                                    workspace.open_resolved_path(path, window, cx)
14954                                })?
14955                                .await
14956                                .map(|_| TargetTaskResult::AlreadyNavigated)
14957                        })
14958                    } else {
14959                        Task::ready(Ok(TargetTaskResult::Location(None)))
14960                    }
14961                }
14962            };
14963            cx.spawn_in(window, async move |editor, cx| {
14964                let target = match target_task.await.context("target resolution task")? {
14965                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14966                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14967                    TargetTaskResult::Location(Some(target)) => target,
14968                };
14969
14970                editor.update_in(cx, |editor, window, cx| {
14971                    let Some(workspace) = editor.workspace() else {
14972                        return Navigated::No;
14973                    };
14974                    let pane = workspace.read(cx).active_pane().clone();
14975
14976                    let range = target.range.to_point(target.buffer.read(cx));
14977                    let range = editor.range_for_match(&range);
14978                    let range = collapse_multiline_range(range);
14979
14980                    if !split
14981                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14982                    {
14983                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14984                    } else {
14985                        window.defer(cx, move |window, cx| {
14986                            let target_editor: Entity<Self> =
14987                                workspace.update(cx, |workspace, cx| {
14988                                    let pane = if split {
14989                                        workspace.adjacent_pane(window, cx)
14990                                    } else {
14991                                        workspace.active_pane().clone()
14992                                    };
14993
14994                                    workspace.open_project_item(
14995                                        pane,
14996                                        target.buffer.clone(),
14997                                        true,
14998                                        true,
14999                                        window,
15000                                        cx,
15001                                    )
15002                                });
15003                            target_editor.update(cx, |target_editor, cx| {
15004                                // When selecting a definition in a different buffer, disable the nav history
15005                                // to avoid creating a history entry at the previous cursor location.
15006                                pane.update(cx, |pane, _| pane.disable_history());
15007                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15008                                pane.update(cx, |pane, _| pane.enable_history());
15009                            });
15010                        });
15011                    }
15012                    Navigated::Yes
15013                })
15014            })
15015        } else if !definitions.is_empty() {
15016            cx.spawn_in(window, async move |editor, cx| {
15017                let (title, location_tasks, workspace) = editor
15018                    .update_in(cx, |editor, window, cx| {
15019                        let tab_kind = match kind {
15020                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15021                            _ => "Definitions",
15022                        };
15023                        let title = definitions
15024                            .iter()
15025                            .find_map(|definition| match definition {
15026                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15027                                    let buffer = origin.buffer.read(cx);
15028                                    format!(
15029                                        "{} for {}",
15030                                        tab_kind,
15031                                        buffer
15032                                            .text_for_range(origin.range.clone())
15033                                            .collect::<String>()
15034                                    )
15035                                }),
15036                                HoverLink::InlayHint(_, _) => None,
15037                                HoverLink::Url(_) => None,
15038                                HoverLink::File(_) => None,
15039                            })
15040                            .unwrap_or(tab_kind.to_string());
15041                        let location_tasks = definitions
15042                            .into_iter()
15043                            .map(|definition| match definition {
15044                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15045                                HoverLink::InlayHint(lsp_location, server_id) => editor
15046                                    .compute_target_location(lsp_location, server_id, window, cx),
15047                                HoverLink::Url(_) => Task::ready(Ok(None)),
15048                                HoverLink::File(_) => Task::ready(Ok(None)),
15049                            })
15050                            .collect::<Vec<_>>();
15051                        (title, location_tasks, editor.workspace().clone())
15052                    })
15053                    .context("location tasks preparation")?;
15054
15055                let locations = future::join_all(location_tasks)
15056                    .await
15057                    .into_iter()
15058                    .filter_map(|location| location.transpose())
15059                    .collect::<Result<_>>()
15060                    .context("location tasks")?;
15061
15062                let Some(workspace) = workspace else {
15063                    return Ok(Navigated::No);
15064                };
15065                let opened = workspace
15066                    .update_in(cx, |workspace, window, cx| {
15067                        Self::open_locations_in_multibuffer(
15068                            workspace,
15069                            locations,
15070                            title,
15071                            split,
15072                            MultibufferSelectionMode::First,
15073                            window,
15074                            cx,
15075                        )
15076                    })
15077                    .ok();
15078
15079                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15080            })
15081        } else {
15082            Task::ready(Ok(Navigated::No))
15083        }
15084    }
15085
15086    fn compute_target_location(
15087        &self,
15088        lsp_location: lsp::Location,
15089        server_id: LanguageServerId,
15090        window: &mut Window,
15091        cx: &mut Context<Self>,
15092    ) -> Task<anyhow::Result<Option<Location>>> {
15093        let Some(project) = self.project.clone() else {
15094            return Task::ready(Ok(None));
15095        };
15096
15097        cx.spawn_in(window, async move |editor, cx| {
15098            let location_task = editor.update(cx, |_, cx| {
15099                project.update(cx, |project, cx| {
15100                    let language_server_name = project
15101                        .language_server_statuses(cx)
15102                        .find(|(id, _)| server_id == *id)
15103                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15104                    language_server_name.map(|language_server_name| {
15105                        project.open_local_buffer_via_lsp(
15106                            lsp_location.uri.clone(),
15107                            server_id,
15108                            language_server_name,
15109                            cx,
15110                        )
15111                    })
15112                })
15113            })?;
15114            let location = match location_task {
15115                Some(task) => Some({
15116                    let target_buffer_handle = task.await.context("open local buffer")?;
15117                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15118                        let target_start = target_buffer
15119                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15120                        let target_end = target_buffer
15121                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15122                        target_buffer.anchor_after(target_start)
15123                            ..target_buffer.anchor_before(target_end)
15124                    })?;
15125                    Location {
15126                        buffer: target_buffer_handle,
15127                        range,
15128                    }
15129                }),
15130                None => None,
15131            };
15132            Ok(location)
15133        })
15134    }
15135
15136    pub fn find_all_references(
15137        &mut self,
15138        _: &FindAllReferences,
15139        window: &mut Window,
15140        cx: &mut Context<Self>,
15141    ) -> Option<Task<Result<Navigated>>> {
15142        let selection = self.selections.newest::<usize>(cx);
15143        let multi_buffer = self.buffer.read(cx);
15144        let head = selection.head();
15145
15146        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15147        let head_anchor = multi_buffer_snapshot.anchor_at(
15148            head,
15149            if head < selection.tail() {
15150                Bias::Right
15151            } else {
15152                Bias::Left
15153            },
15154        );
15155
15156        match self
15157            .find_all_references_task_sources
15158            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15159        {
15160            Ok(_) => {
15161                log::info!(
15162                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15163                );
15164                return None;
15165            }
15166            Err(i) => {
15167                self.find_all_references_task_sources.insert(i, head_anchor);
15168            }
15169        }
15170
15171        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15172        let workspace = self.workspace()?;
15173        let project = workspace.read(cx).project().clone();
15174        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15175        Some(cx.spawn_in(window, async move |editor, cx| {
15176            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15177                if let Ok(i) = editor
15178                    .find_all_references_task_sources
15179                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15180                {
15181                    editor.find_all_references_task_sources.remove(i);
15182                }
15183            });
15184
15185            let locations = references.await?;
15186            if locations.is_empty() {
15187                return anyhow::Ok(Navigated::No);
15188            }
15189
15190            workspace.update_in(cx, |workspace, window, cx| {
15191                let title = locations
15192                    .first()
15193                    .as_ref()
15194                    .map(|location| {
15195                        let buffer = location.buffer.read(cx);
15196                        format!(
15197                            "References to `{}`",
15198                            buffer
15199                                .text_for_range(location.range.clone())
15200                                .collect::<String>()
15201                        )
15202                    })
15203                    .unwrap();
15204                Self::open_locations_in_multibuffer(
15205                    workspace,
15206                    locations,
15207                    title,
15208                    false,
15209                    MultibufferSelectionMode::First,
15210                    window,
15211                    cx,
15212                );
15213                Navigated::Yes
15214            })
15215        }))
15216    }
15217
15218    /// Opens a multibuffer with the given project locations in it
15219    pub fn open_locations_in_multibuffer(
15220        workspace: &mut Workspace,
15221        mut locations: Vec<Location>,
15222        title: String,
15223        split: bool,
15224        multibuffer_selection_mode: MultibufferSelectionMode,
15225        window: &mut Window,
15226        cx: &mut Context<Workspace>,
15227    ) {
15228        // If there are multiple definitions, open them in a multibuffer
15229        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15230        let mut locations = locations.into_iter().peekable();
15231        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15232        let capability = workspace.project().read(cx).capability();
15233
15234        let excerpt_buffer = cx.new(|cx| {
15235            let mut multibuffer = MultiBuffer::new(capability);
15236            while let Some(location) = locations.next() {
15237                let buffer = location.buffer.read(cx);
15238                let mut ranges_for_buffer = Vec::new();
15239                let range = location.range.to_point(buffer);
15240                ranges_for_buffer.push(range.clone());
15241
15242                while let Some(next_location) = locations.peek() {
15243                    if next_location.buffer == location.buffer {
15244                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15245                        locations.next();
15246                    } else {
15247                        break;
15248                    }
15249                }
15250
15251                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15252                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15253                    PathKey::for_buffer(&location.buffer, cx),
15254                    location.buffer.clone(),
15255                    ranges_for_buffer,
15256                    DEFAULT_MULTIBUFFER_CONTEXT,
15257                    cx,
15258                );
15259                ranges.extend(new_ranges)
15260            }
15261
15262            multibuffer.with_title(title)
15263        });
15264
15265        let editor = cx.new(|cx| {
15266            Editor::for_multibuffer(
15267                excerpt_buffer,
15268                Some(workspace.project().clone()),
15269                window,
15270                cx,
15271            )
15272        });
15273        editor.update(cx, |editor, cx| {
15274            match multibuffer_selection_mode {
15275                MultibufferSelectionMode::First => {
15276                    if let Some(first_range) = ranges.first() {
15277                        editor.change_selections(None, window, cx, |selections| {
15278                            selections.clear_disjoint();
15279                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15280                        });
15281                    }
15282                    editor.highlight_background::<Self>(
15283                        &ranges,
15284                        |theme| theme.editor_highlighted_line_background,
15285                        cx,
15286                    );
15287                }
15288                MultibufferSelectionMode::All => {
15289                    editor.change_selections(None, window, cx, |selections| {
15290                        selections.clear_disjoint();
15291                        selections.select_anchor_ranges(ranges);
15292                    });
15293                }
15294            }
15295            editor.register_buffers_with_language_servers(cx);
15296        });
15297
15298        let item = Box::new(editor);
15299        let item_id = item.item_id();
15300
15301        if split {
15302            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15303        } else {
15304            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15305                let (preview_item_id, preview_item_idx) =
15306                    workspace.active_pane().read_with(cx, |pane, _| {
15307                        (pane.preview_item_id(), pane.preview_item_idx())
15308                    });
15309
15310                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15311
15312                if let Some(preview_item_id) = preview_item_id {
15313                    workspace.active_pane().update(cx, |pane, cx| {
15314                        pane.remove_item(preview_item_id, false, false, window, cx);
15315                    });
15316                }
15317            } else {
15318                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15319            }
15320        }
15321        workspace.active_pane().update(cx, |pane, cx| {
15322            pane.set_preview_item_id(Some(item_id), cx);
15323        });
15324    }
15325
15326    pub fn rename(
15327        &mut self,
15328        _: &Rename,
15329        window: &mut Window,
15330        cx: &mut Context<Self>,
15331    ) -> Option<Task<Result<()>>> {
15332        use language::ToOffset as _;
15333
15334        let provider = self.semantics_provider.clone()?;
15335        let selection = self.selections.newest_anchor().clone();
15336        let (cursor_buffer, cursor_buffer_position) = self
15337            .buffer
15338            .read(cx)
15339            .text_anchor_for_position(selection.head(), cx)?;
15340        let (tail_buffer, cursor_buffer_position_end) = self
15341            .buffer
15342            .read(cx)
15343            .text_anchor_for_position(selection.tail(), cx)?;
15344        if tail_buffer != cursor_buffer {
15345            return None;
15346        }
15347
15348        let snapshot = cursor_buffer.read(cx).snapshot();
15349        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15350        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15351        let prepare_rename = provider
15352            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15353            .unwrap_or_else(|| Task::ready(Ok(None)));
15354        drop(snapshot);
15355
15356        Some(cx.spawn_in(window, async move |this, cx| {
15357            let rename_range = if let Some(range) = prepare_rename.await? {
15358                Some(range)
15359            } else {
15360                this.update(cx, |this, cx| {
15361                    let buffer = this.buffer.read(cx).snapshot(cx);
15362                    let mut buffer_highlights = this
15363                        .document_highlights_for_position(selection.head(), &buffer)
15364                        .filter(|highlight| {
15365                            highlight.start.excerpt_id == selection.head().excerpt_id
15366                                && highlight.end.excerpt_id == selection.head().excerpt_id
15367                        });
15368                    buffer_highlights
15369                        .next()
15370                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15371                })?
15372            };
15373            if let Some(rename_range) = rename_range {
15374                this.update_in(cx, |this, window, cx| {
15375                    let snapshot = cursor_buffer.read(cx).snapshot();
15376                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15377                    let cursor_offset_in_rename_range =
15378                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15379                    let cursor_offset_in_rename_range_end =
15380                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15381
15382                    this.take_rename(false, window, cx);
15383                    let buffer = this.buffer.read(cx).read(cx);
15384                    let cursor_offset = selection.head().to_offset(&buffer);
15385                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15386                    let rename_end = rename_start + rename_buffer_range.len();
15387                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15388                    let mut old_highlight_id = None;
15389                    let old_name: Arc<str> = buffer
15390                        .chunks(rename_start..rename_end, true)
15391                        .map(|chunk| {
15392                            if old_highlight_id.is_none() {
15393                                old_highlight_id = chunk.syntax_highlight_id;
15394                            }
15395                            chunk.text
15396                        })
15397                        .collect::<String>()
15398                        .into();
15399
15400                    drop(buffer);
15401
15402                    // Position the selection in the rename editor so that it matches the current selection.
15403                    this.show_local_selections = false;
15404                    let rename_editor = cx.new(|cx| {
15405                        let mut editor = Editor::single_line(window, cx);
15406                        editor.buffer.update(cx, |buffer, cx| {
15407                            buffer.edit([(0..0, old_name.clone())], None, cx)
15408                        });
15409                        let rename_selection_range = match cursor_offset_in_rename_range
15410                            .cmp(&cursor_offset_in_rename_range_end)
15411                        {
15412                            Ordering::Equal => {
15413                                editor.select_all(&SelectAll, window, cx);
15414                                return editor;
15415                            }
15416                            Ordering::Less => {
15417                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15418                            }
15419                            Ordering::Greater => {
15420                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15421                            }
15422                        };
15423                        if rename_selection_range.end > old_name.len() {
15424                            editor.select_all(&SelectAll, window, cx);
15425                        } else {
15426                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15427                                s.select_ranges([rename_selection_range]);
15428                            });
15429                        }
15430                        editor
15431                    });
15432                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15433                        if e == &EditorEvent::Focused {
15434                            cx.emit(EditorEvent::FocusedIn)
15435                        }
15436                    })
15437                    .detach();
15438
15439                    let write_highlights =
15440                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15441                    let read_highlights =
15442                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15443                    let ranges = write_highlights
15444                        .iter()
15445                        .flat_map(|(_, ranges)| ranges.iter())
15446                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15447                        .cloned()
15448                        .collect();
15449
15450                    this.highlight_text::<Rename>(
15451                        ranges,
15452                        HighlightStyle {
15453                            fade_out: Some(0.6),
15454                            ..Default::default()
15455                        },
15456                        cx,
15457                    );
15458                    let rename_focus_handle = rename_editor.focus_handle(cx);
15459                    window.focus(&rename_focus_handle);
15460                    let block_id = this.insert_blocks(
15461                        [BlockProperties {
15462                            style: BlockStyle::Flex,
15463                            placement: BlockPlacement::Below(range.start),
15464                            height: Some(1),
15465                            render: Arc::new({
15466                                let rename_editor = rename_editor.clone();
15467                                move |cx: &mut BlockContext| {
15468                                    let mut text_style = cx.editor_style.text.clone();
15469                                    if let Some(highlight_style) = old_highlight_id
15470                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15471                                    {
15472                                        text_style = text_style.highlight(highlight_style);
15473                                    }
15474                                    div()
15475                                        .block_mouse_except_scroll()
15476                                        .pl(cx.anchor_x)
15477                                        .child(EditorElement::new(
15478                                            &rename_editor,
15479                                            EditorStyle {
15480                                                background: cx.theme().system().transparent,
15481                                                local_player: cx.editor_style.local_player,
15482                                                text: text_style,
15483                                                scrollbar_width: cx.editor_style.scrollbar_width,
15484                                                syntax: cx.editor_style.syntax.clone(),
15485                                                status: cx.editor_style.status.clone(),
15486                                                inlay_hints_style: HighlightStyle {
15487                                                    font_weight: Some(FontWeight::BOLD),
15488                                                    ..make_inlay_hints_style(cx.app)
15489                                                },
15490                                                inline_completion_styles: make_suggestion_styles(
15491                                                    cx.app,
15492                                                ),
15493                                                ..EditorStyle::default()
15494                                            },
15495                                        ))
15496                                        .into_any_element()
15497                                }
15498                            }),
15499                            priority: 0,
15500                            render_in_minimap: true,
15501                        }],
15502                        Some(Autoscroll::fit()),
15503                        cx,
15504                    )[0];
15505                    this.pending_rename = Some(RenameState {
15506                        range,
15507                        old_name,
15508                        editor: rename_editor,
15509                        block_id,
15510                    });
15511                })?;
15512            }
15513
15514            Ok(())
15515        }))
15516    }
15517
15518    pub fn confirm_rename(
15519        &mut self,
15520        _: &ConfirmRename,
15521        window: &mut Window,
15522        cx: &mut Context<Self>,
15523    ) -> Option<Task<Result<()>>> {
15524        let rename = self.take_rename(false, window, cx)?;
15525        let workspace = self.workspace()?.downgrade();
15526        let (buffer, start) = self
15527            .buffer
15528            .read(cx)
15529            .text_anchor_for_position(rename.range.start, cx)?;
15530        let (end_buffer, _) = self
15531            .buffer
15532            .read(cx)
15533            .text_anchor_for_position(rename.range.end, cx)?;
15534        if buffer != end_buffer {
15535            return None;
15536        }
15537
15538        let old_name = rename.old_name;
15539        let new_name = rename.editor.read(cx).text(cx);
15540
15541        let rename = self.semantics_provider.as_ref()?.perform_rename(
15542            &buffer,
15543            start,
15544            new_name.clone(),
15545            cx,
15546        )?;
15547
15548        Some(cx.spawn_in(window, async move |editor, cx| {
15549            let project_transaction = rename.await?;
15550            Self::open_project_transaction(
15551                &editor,
15552                workspace,
15553                project_transaction,
15554                format!("Rename: {}{}", old_name, new_name),
15555                cx,
15556            )
15557            .await?;
15558
15559            editor.update(cx, |editor, cx| {
15560                editor.refresh_document_highlights(cx);
15561            })?;
15562            Ok(())
15563        }))
15564    }
15565
15566    fn take_rename(
15567        &mut self,
15568        moving_cursor: bool,
15569        window: &mut Window,
15570        cx: &mut Context<Self>,
15571    ) -> Option<RenameState> {
15572        let rename = self.pending_rename.take()?;
15573        if rename.editor.focus_handle(cx).is_focused(window) {
15574            window.focus(&self.focus_handle);
15575        }
15576
15577        self.remove_blocks(
15578            [rename.block_id].into_iter().collect(),
15579            Some(Autoscroll::fit()),
15580            cx,
15581        );
15582        self.clear_highlights::<Rename>(cx);
15583        self.show_local_selections = true;
15584
15585        if moving_cursor {
15586            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15587                editor.selections.newest::<usize>(cx).head()
15588            });
15589
15590            // Update the selection to match the position of the selection inside
15591            // the rename editor.
15592            let snapshot = self.buffer.read(cx).read(cx);
15593            let rename_range = rename.range.to_offset(&snapshot);
15594            let cursor_in_editor = snapshot
15595                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15596                .min(rename_range.end);
15597            drop(snapshot);
15598
15599            self.change_selections(None, window, cx, |s| {
15600                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15601            });
15602        } else {
15603            self.refresh_document_highlights(cx);
15604        }
15605
15606        Some(rename)
15607    }
15608
15609    pub fn pending_rename(&self) -> Option<&RenameState> {
15610        self.pending_rename.as_ref()
15611    }
15612
15613    fn format(
15614        &mut self,
15615        _: &Format,
15616        window: &mut Window,
15617        cx: &mut Context<Self>,
15618    ) -> Option<Task<Result<()>>> {
15619        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15620
15621        let project = match &self.project {
15622            Some(project) => project.clone(),
15623            None => return None,
15624        };
15625
15626        Some(self.perform_format(
15627            project,
15628            FormatTrigger::Manual,
15629            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15630            window,
15631            cx,
15632        ))
15633    }
15634
15635    fn format_selections(
15636        &mut self,
15637        _: &FormatSelections,
15638        window: &mut Window,
15639        cx: &mut Context<Self>,
15640    ) -> Option<Task<Result<()>>> {
15641        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15642
15643        let project = match &self.project {
15644            Some(project) => project.clone(),
15645            None => return None,
15646        };
15647
15648        let ranges = self
15649            .selections
15650            .all_adjusted(cx)
15651            .into_iter()
15652            .map(|selection| selection.range())
15653            .collect_vec();
15654
15655        Some(self.perform_format(
15656            project,
15657            FormatTrigger::Manual,
15658            FormatTarget::Ranges(ranges),
15659            window,
15660            cx,
15661        ))
15662    }
15663
15664    fn perform_format(
15665        &mut self,
15666        project: Entity<Project>,
15667        trigger: FormatTrigger,
15668        target: FormatTarget,
15669        window: &mut Window,
15670        cx: &mut Context<Self>,
15671    ) -> Task<Result<()>> {
15672        let buffer = self.buffer.clone();
15673        let (buffers, target) = match target {
15674            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15675            FormatTarget::Ranges(selection_ranges) => {
15676                let multi_buffer = buffer.read(cx);
15677                let snapshot = multi_buffer.read(cx);
15678                let mut buffers = HashSet::default();
15679                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15680                    BTreeMap::new();
15681                for selection_range in selection_ranges {
15682                    for (buffer, buffer_range, _) in
15683                        snapshot.range_to_buffer_ranges(selection_range)
15684                    {
15685                        let buffer_id = buffer.remote_id();
15686                        let start = buffer.anchor_before(buffer_range.start);
15687                        let end = buffer.anchor_after(buffer_range.end);
15688                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15689                        buffer_id_to_ranges
15690                            .entry(buffer_id)
15691                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15692                            .or_insert_with(|| vec![start..end]);
15693                    }
15694                }
15695                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15696            }
15697        };
15698
15699        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15700        let selections_prev = transaction_id_prev
15701            .and_then(|transaction_id_prev| {
15702                // default to selections as they were after the last edit, if we have them,
15703                // instead of how they are now.
15704                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15705                // will take you back to where you made the last edit, instead of staying where you scrolled
15706                self.selection_history
15707                    .transaction(transaction_id_prev)
15708                    .map(|t| t.0.clone())
15709            })
15710            .unwrap_or_else(|| {
15711                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15712                self.selections.disjoint_anchors()
15713            });
15714
15715        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15716        let format = project.update(cx, |project, cx| {
15717            project.format(buffers, target, true, trigger, cx)
15718        });
15719
15720        cx.spawn_in(window, async move |editor, cx| {
15721            let transaction = futures::select_biased! {
15722                transaction = format.log_err().fuse() => transaction,
15723                () = timeout => {
15724                    log::warn!("timed out waiting for formatting");
15725                    None
15726                }
15727            };
15728
15729            buffer
15730                .update(cx, |buffer, cx| {
15731                    if let Some(transaction) = transaction {
15732                        if !buffer.is_singleton() {
15733                            buffer.push_transaction(&transaction.0, cx);
15734                        }
15735                    }
15736                    cx.notify();
15737                })
15738                .ok();
15739
15740            if let Some(transaction_id_now) =
15741                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15742            {
15743                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15744                if has_new_transaction {
15745                    _ = editor.update(cx, |editor, _| {
15746                        editor
15747                            .selection_history
15748                            .insert_transaction(transaction_id_now, selections_prev);
15749                    });
15750                }
15751            }
15752
15753            Ok(())
15754        })
15755    }
15756
15757    fn organize_imports(
15758        &mut self,
15759        _: &OrganizeImports,
15760        window: &mut Window,
15761        cx: &mut Context<Self>,
15762    ) -> Option<Task<Result<()>>> {
15763        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15764        let project = match &self.project {
15765            Some(project) => project.clone(),
15766            None => return None,
15767        };
15768        Some(self.perform_code_action_kind(
15769            project,
15770            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15771            window,
15772            cx,
15773        ))
15774    }
15775
15776    fn perform_code_action_kind(
15777        &mut self,
15778        project: Entity<Project>,
15779        kind: CodeActionKind,
15780        window: &mut Window,
15781        cx: &mut Context<Self>,
15782    ) -> Task<Result<()>> {
15783        let buffer = self.buffer.clone();
15784        let buffers = buffer.read(cx).all_buffers();
15785        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15786        let apply_action = project.update(cx, |project, cx| {
15787            project.apply_code_action_kind(buffers, kind, true, cx)
15788        });
15789        cx.spawn_in(window, async move |_, cx| {
15790            let transaction = futures::select_biased! {
15791                () = timeout => {
15792                    log::warn!("timed out waiting for executing code action");
15793                    None
15794                }
15795                transaction = apply_action.log_err().fuse() => transaction,
15796            };
15797            buffer
15798                .update(cx, |buffer, cx| {
15799                    // check if we need this
15800                    if let Some(transaction) = transaction {
15801                        if !buffer.is_singleton() {
15802                            buffer.push_transaction(&transaction.0, cx);
15803                        }
15804                    }
15805                    cx.notify();
15806                })
15807                .ok();
15808            Ok(())
15809        })
15810    }
15811
15812    fn restart_language_server(
15813        &mut self,
15814        _: &RestartLanguageServer,
15815        _: &mut Window,
15816        cx: &mut Context<Self>,
15817    ) {
15818        if let Some(project) = self.project.clone() {
15819            self.buffer.update(cx, |multi_buffer, cx| {
15820                project.update(cx, |project, cx| {
15821                    project.restart_language_servers_for_buffers(
15822                        multi_buffer.all_buffers().into_iter().collect(),
15823                        cx,
15824                    );
15825                });
15826            })
15827        }
15828    }
15829
15830    fn stop_language_server(
15831        &mut self,
15832        _: &StopLanguageServer,
15833        _: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        if let Some(project) = self.project.clone() {
15837            self.buffer.update(cx, |multi_buffer, cx| {
15838                project.update(cx, |project, cx| {
15839                    project.stop_language_servers_for_buffers(
15840                        multi_buffer.all_buffers().into_iter().collect(),
15841                        cx,
15842                    );
15843                    cx.emit(project::Event::RefreshInlayHints);
15844                });
15845            });
15846        }
15847    }
15848
15849    fn cancel_language_server_work(
15850        workspace: &mut Workspace,
15851        _: &actions::CancelLanguageServerWork,
15852        _: &mut Window,
15853        cx: &mut Context<Workspace>,
15854    ) {
15855        let project = workspace.project();
15856        let buffers = workspace
15857            .active_item(cx)
15858            .and_then(|item| item.act_as::<Editor>(cx))
15859            .map_or(HashSet::default(), |editor| {
15860                editor.read(cx).buffer.read(cx).all_buffers()
15861            });
15862        project.update(cx, |project, cx| {
15863            project.cancel_language_server_work_for_buffers(buffers, cx);
15864        });
15865    }
15866
15867    fn show_character_palette(
15868        &mut self,
15869        _: &ShowCharacterPalette,
15870        window: &mut Window,
15871        _: &mut Context<Self>,
15872    ) {
15873        window.show_character_palette();
15874    }
15875
15876    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15877        if self.mode.is_minimap() {
15878            return;
15879        }
15880
15881        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15882            let buffer = self.buffer.read(cx).snapshot(cx);
15883            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15884            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15885            let is_valid = buffer
15886                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15887                .any(|entry| {
15888                    entry.diagnostic.is_primary
15889                        && !entry.range.is_empty()
15890                        && entry.range.start == primary_range_start
15891                        && entry.diagnostic.message == active_diagnostics.active_message
15892                });
15893
15894            if !is_valid {
15895                self.dismiss_diagnostics(cx);
15896            }
15897        }
15898    }
15899
15900    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15901        match &self.active_diagnostics {
15902            ActiveDiagnostic::Group(group) => Some(group),
15903            _ => None,
15904        }
15905    }
15906
15907    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15908        self.dismiss_diagnostics(cx);
15909        self.active_diagnostics = ActiveDiagnostic::All;
15910    }
15911
15912    fn activate_diagnostics(
15913        &mut self,
15914        buffer_id: BufferId,
15915        diagnostic: DiagnosticEntry<usize>,
15916        window: &mut Window,
15917        cx: &mut Context<Self>,
15918    ) {
15919        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15920            return;
15921        }
15922        self.dismiss_diagnostics(cx);
15923        let snapshot = self.snapshot(window, cx);
15924        let buffer = self.buffer.read(cx).snapshot(cx);
15925        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15926            return;
15927        };
15928
15929        let diagnostic_group = buffer
15930            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15931            .collect::<Vec<_>>();
15932
15933        let blocks =
15934            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15935
15936        let blocks = self.display_map.update(cx, |display_map, cx| {
15937            display_map.insert_blocks(blocks, cx).into_iter().collect()
15938        });
15939        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15940            active_range: buffer.anchor_before(diagnostic.range.start)
15941                ..buffer.anchor_after(diagnostic.range.end),
15942            active_message: diagnostic.diagnostic.message.clone(),
15943            group_id: diagnostic.diagnostic.group_id,
15944            blocks,
15945        });
15946        cx.notify();
15947    }
15948
15949    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15950        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15951            return;
15952        };
15953
15954        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15955        if let ActiveDiagnostic::Group(group) = prev {
15956            self.display_map.update(cx, |display_map, cx| {
15957                display_map.remove_blocks(group.blocks, cx);
15958            });
15959            cx.notify();
15960        }
15961    }
15962
15963    /// Disable inline diagnostics rendering for this editor.
15964    pub fn disable_inline_diagnostics(&mut self) {
15965        self.inline_diagnostics_enabled = false;
15966        self.inline_diagnostics_update = Task::ready(());
15967        self.inline_diagnostics.clear();
15968    }
15969
15970    pub fn diagnostics_enabled(&self) -> bool {
15971        self.mode.is_full()
15972    }
15973
15974    pub fn inline_diagnostics_enabled(&self) -> bool {
15975        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15976    }
15977
15978    pub fn show_inline_diagnostics(&self) -> bool {
15979        self.show_inline_diagnostics
15980    }
15981
15982    pub fn toggle_inline_diagnostics(
15983        &mut self,
15984        _: &ToggleInlineDiagnostics,
15985        window: &mut Window,
15986        cx: &mut Context<Editor>,
15987    ) {
15988        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15989        self.refresh_inline_diagnostics(false, window, cx);
15990    }
15991
15992    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15993        self.diagnostics_max_severity = severity;
15994        self.display_map.update(cx, |display_map, _| {
15995            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15996        });
15997    }
15998
15999    pub fn toggle_diagnostics(
16000        &mut self,
16001        _: &ToggleDiagnostics,
16002        window: &mut Window,
16003        cx: &mut Context<Editor>,
16004    ) {
16005        if !self.diagnostics_enabled() {
16006            return;
16007        }
16008
16009        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16010            EditorSettings::get_global(cx)
16011                .diagnostics_max_severity
16012                .filter(|severity| severity != &DiagnosticSeverity::Off)
16013                .unwrap_or(DiagnosticSeverity::Hint)
16014        } else {
16015            DiagnosticSeverity::Off
16016        };
16017        self.set_max_diagnostics_severity(new_severity, cx);
16018        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16019            self.active_diagnostics = ActiveDiagnostic::None;
16020            self.inline_diagnostics_update = Task::ready(());
16021            self.inline_diagnostics.clear();
16022        } else {
16023            self.refresh_inline_diagnostics(false, window, cx);
16024        }
16025
16026        cx.notify();
16027    }
16028
16029    pub fn toggle_minimap(
16030        &mut self,
16031        _: &ToggleMinimap,
16032        window: &mut Window,
16033        cx: &mut Context<Editor>,
16034    ) {
16035        if self.supports_minimap(cx) {
16036            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16037        }
16038    }
16039
16040    fn refresh_inline_diagnostics(
16041        &mut self,
16042        debounce: bool,
16043        window: &mut Window,
16044        cx: &mut Context<Self>,
16045    ) {
16046        let max_severity = ProjectSettings::get_global(cx)
16047            .diagnostics
16048            .inline
16049            .max_severity
16050            .unwrap_or(self.diagnostics_max_severity);
16051
16052        if !self.inline_diagnostics_enabled()
16053            || !self.show_inline_diagnostics
16054            || max_severity == DiagnosticSeverity::Off
16055        {
16056            self.inline_diagnostics_update = Task::ready(());
16057            self.inline_diagnostics.clear();
16058            return;
16059        }
16060
16061        let debounce_ms = ProjectSettings::get_global(cx)
16062            .diagnostics
16063            .inline
16064            .update_debounce_ms;
16065        let debounce = if debounce && debounce_ms > 0 {
16066            Some(Duration::from_millis(debounce_ms))
16067        } else {
16068            None
16069        };
16070        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16071            if let Some(debounce) = debounce {
16072                cx.background_executor().timer(debounce).await;
16073            }
16074            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16075                editor
16076                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16077                    .ok()
16078            }) else {
16079                return;
16080            };
16081
16082            let new_inline_diagnostics = cx
16083                .background_spawn(async move {
16084                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16085                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16086                        let message = diagnostic_entry
16087                            .diagnostic
16088                            .message
16089                            .split_once('\n')
16090                            .map(|(line, _)| line)
16091                            .map(SharedString::new)
16092                            .unwrap_or_else(|| {
16093                                SharedString::from(diagnostic_entry.diagnostic.message)
16094                            });
16095                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16096                        let (Ok(i) | Err(i)) = inline_diagnostics
16097                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16098                        inline_diagnostics.insert(
16099                            i,
16100                            (
16101                                start_anchor,
16102                                InlineDiagnostic {
16103                                    message,
16104                                    group_id: diagnostic_entry.diagnostic.group_id,
16105                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16106                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16107                                    severity: diagnostic_entry.diagnostic.severity,
16108                                },
16109                            ),
16110                        );
16111                    }
16112                    inline_diagnostics
16113                })
16114                .await;
16115
16116            editor
16117                .update(cx, |editor, cx| {
16118                    editor.inline_diagnostics = new_inline_diagnostics;
16119                    cx.notify();
16120                })
16121                .ok();
16122        });
16123    }
16124
16125    fn pull_diagnostics(
16126        &mut self,
16127        buffer_id: Option<BufferId>,
16128        window: &Window,
16129        cx: &mut Context<Self>,
16130    ) -> Option<()> {
16131        if !self.mode().is_full() {
16132            return None;
16133        }
16134        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16135            .diagnostics
16136            .lsp_pull_diagnostics;
16137        if !pull_diagnostics_settings.enabled {
16138            return None;
16139        }
16140        let project = self.project.as_ref()?.downgrade();
16141        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16142        let mut buffers = self.buffer.read(cx).all_buffers();
16143        if let Some(buffer_id) = buffer_id {
16144            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16145        }
16146
16147        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16148            cx.background_executor().timer(debounce).await;
16149
16150            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16151                buffers
16152                    .into_iter()
16153                    .flat_map(|buffer| {
16154                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16155                    })
16156                    .collect::<FuturesUnordered<_>>()
16157            }) else {
16158                return;
16159            };
16160
16161            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16162                match pull_task {
16163                    Ok(()) => {
16164                        if editor
16165                            .update_in(cx, |editor, window, cx| {
16166                                editor.update_diagnostics_state(window, cx);
16167                            })
16168                            .is_err()
16169                        {
16170                            return;
16171                        }
16172                    }
16173                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16174                }
16175            }
16176        });
16177
16178        Some(())
16179    }
16180
16181    pub fn set_selections_from_remote(
16182        &mut self,
16183        selections: Vec<Selection<Anchor>>,
16184        pending_selection: Option<Selection<Anchor>>,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) {
16188        let old_cursor_position = self.selections.newest_anchor().head();
16189        self.selections.change_with(cx, |s| {
16190            s.select_anchors(selections);
16191            if let Some(pending_selection) = pending_selection {
16192                s.set_pending(pending_selection, SelectMode::Character);
16193            } else {
16194                s.clear_pending();
16195            }
16196        });
16197        self.selections_did_change(
16198            false,
16199            &old_cursor_position,
16200            SelectionEffects::default(),
16201            window,
16202            cx,
16203        );
16204    }
16205
16206    pub fn transact(
16207        &mut self,
16208        window: &mut Window,
16209        cx: &mut Context<Self>,
16210        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16211    ) -> Option<TransactionId> {
16212        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16213            this.start_transaction_at(Instant::now(), window, cx);
16214            update(this, window, cx);
16215            this.end_transaction_at(Instant::now(), cx)
16216        })
16217    }
16218
16219    pub fn start_transaction_at(
16220        &mut self,
16221        now: Instant,
16222        window: &mut Window,
16223        cx: &mut Context<Self>,
16224    ) {
16225        self.end_selection(window, cx);
16226        if let Some(tx_id) = self
16227            .buffer
16228            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16229        {
16230            self.selection_history
16231                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16232            cx.emit(EditorEvent::TransactionBegun {
16233                transaction_id: tx_id,
16234            })
16235        }
16236    }
16237
16238    pub fn end_transaction_at(
16239        &mut self,
16240        now: Instant,
16241        cx: &mut Context<Self>,
16242    ) -> Option<TransactionId> {
16243        if let Some(transaction_id) = self
16244            .buffer
16245            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16246        {
16247            if let Some((_, end_selections)) =
16248                self.selection_history.transaction_mut(transaction_id)
16249            {
16250                *end_selections = Some(self.selections.disjoint_anchors());
16251            } else {
16252                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16253            }
16254
16255            cx.emit(EditorEvent::Edited { transaction_id });
16256            Some(transaction_id)
16257        } else {
16258            None
16259        }
16260    }
16261
16262    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16263        if self.selection_mark_mode {
16264            self.change_selections(None, window, cx, |s| {
16265                s.move_with(|_, sel| {
16266                    sel.collapse_to(sel.head(), SelectionGoal::None);
16267                });
16268            })
16269        }
16270        self.selection_mark_mode = true;
16271        cx.notify();
16272    }
16273
16274    pub fn swap_selection_ends(
16275        &mut self,
16276        _: &actions::SwapSelectionEnds,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        self.change_selections(None, window, cx, |s| {
16281            s.move_with(|_, sel| {
16282                if sel.start != sel.end {
16283                    sel.reversed = !sel.reversed
16284                }
16285            });
16286        });
16287        self.request_autoscroll(Autoscroll::newest(), cx);
16288        cx.notify();
16289    }
16290
16291    pub fn toggle_fold(
16292        &mut self,
16293        _: &actions::ToggleFold,
16294        window: &mut Window,
16295        cx: &mut Context<Self>,
16296    ) {
16297        if self.is_singleton(cx) {
16298            let selection = self.selections.newest::<Point>(cx);
16299
16300            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16301            let range = if selection.is_empty() {
16302                let point = selection.head().to_display_point(&display_map);
16303                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16304                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16305                    .to_point(&display_map);
16306                start..end
16307            } else {
16308                selection.range()
16309            };
16310            if display_map.folds_in_range(range).next().is_some() {
16311                self.unfold_lines(&Default::default(), window, cx)
16312            } else {
16313                self.fold(&Default::default(), window, cx)
16314            }
16315        } else {
16316            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16317            let buffer_ids: HashSet<_> = self
16318                .selections
16319                .disjoint_anchor_ranges()
16320                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16321                .collect();
16322
16323            let should_unfold = buffer_ids
16324                .iter()
16325                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16326
16327            for buffer_id in buffer_ids {
16328                if should_unfold {
16329                    self.unfold_buffer(buffer_id, cx);
16330                } else {
16331                    self.fold_buffer(buffer_id, cx);
16332                }
16333            }
16334        }
16335    }
16336
16337    pub fn toggle_fold_recursive(
16338        &mut self,
16339        _: &actions::ToggleFoldRecursive,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) {
16343        let selection = self.selections.newest::<Point>(cx);
16344
16345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16346        let range = if selection.is_empty() {
16347            let point = selection.head().to_display_point(&display_map);
16348            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16349            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16350                .to_point(&display_map);
16351            start..end
16352        } else {
16353            selection.range()
16354        };
16355        if display_map.folds_in_range(range).next().is_some() {
16356            self.unfold_recursive(&Default::default(), window, cx)
16357        } else {
16358            self.fold_recursive(&Default::default(), window, cx)
16359        }
16360    }
16361
16362    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16363        if self.is_singleton(cx) {
16364            let mut to_fold = Vec::new();
16365            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16366            let selections = self.selections.all_adjusted(cx);
16367
16368            for selection in selections {
16369                let range = selection.range().sorted();
16370                let buffer_start_row = range.start.row;
16371
16372                if range.start.row != range.end.row {
16373                    let mut found = false;
16374                    let mut row = range.start.row;
16375                    while row <= range.end.row {
16376                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16377                        {
16378                            found = true;
16379                            row = crease.range().end.row + 1;
16380                            to_fold.push(crease);
16381                        } else {
16382                            row += 1
16383                        }
16384                    }
16385                    if found {
16386                        continue;
16387                    }
16388                }
16389
16390                for row in (0..=range.start.row).rev() {
16391                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16392                        if crease.range().end.row >= buffer_start_row {
16393                            to_fold.push(crease);
16394                            if row <= range.start.row {
16395                                break;
16396                            }
16397                        }
16398                    }
16399                }
16400            }
16401
16402            self.fold_creases(to_fold, true, window, cx);
16403        } else {
16404            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16405            let buffer_ids = self
16406                .selections
16407                .disjoint_anchor_ranges()
16408                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16409                .collect::<HashSet<_>>();
16410            for buffer_id in buffer_ids {
16411                self.fold_buffer(buffer_id, cx);
16412            }
16413        }
16414    }
16415
16416    fn fold_at_level(
16417        &mut self,
16418        fold_at: &FoldAtLevel,
16419        window: &mut Window,
16420        cx: &mut Context<Self>,
16421    ) {
16422        if !self.buffer.read(cx).is_singleton() {
16423            return;
16424        }
16425
16426        let fold_at_level = fold_at.0;
16427        let snapshot = self.buffer.read(cx).snapshot(cx);
16428        let mut to_fold = Vec::new();
16429        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16430
16431        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16432            while start_row < end_row {
16433                match self
16434                    .snapshot(window, cx)
16435                    .crease_for_buffer_row(MultiBufferRow(start_row))
16436                {
16437                    Some(crease) => {
16438                        let nested_start_row = crease.range().start.row + 1;
16439                        let nested_end_row = crease.range().end.row;
16440
16441                        if current_level < fold_at_level {
16442                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16443                        } else if current_level == fold_at_level {
16444                            to_fold.push(crease);
16445                        }
16446
16447                        start_row = nested_end_row + 1;
16448                    }
16449                    None => start_row += 1,
16450                }
16451            }
16452        }
16453
16454        self.fold_creases(to_fold, true, window, cx);
16455    }
16456
16457    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16458        if self.buffer.read(cx).is_singleton() {
16459            let mut fold_ranges = Vec::new();
16460            let snapshot = self.buffer.read(cx).snapshot(cx);
16461
16462            for row in 0..snapshot.max_row().0 {
16463                if let Some(foldable_range) = self
16464                    .snapshot(window, cx)
16465                    .crease_for_buffer_row(MultiBufferRow(row))
16466                {
16467                    fold_ranges.push(foldable_range);
16468                }
16469            }
16470
16471            self.fold_creases(fold_ranges, true, window, cx);
16472        } else {
16473            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16474                editor
16475                    .update_in(cx, |editor, _, cx| {
16476                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16477                            editor.fold_buffer(buffer_id, cx);
16478                        }
16479                    })
16480                    .ok();
16481            });
16482        }
16483    }
16484
16485    pub fn fold_function_bodies(
16486        &mut self,
16487        _: &actions::FoldFunctionBodies,
16488        window: &mut Window,
16489        cx: &mut Context<Self>,
16490    ) {
16491        let snapshot = self.buffer.read(cx).snapshot(cx);
16492
16493        let ranges = snapshot
16494            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16495            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16496            .collect::<Vec<_>>();
16497
16498        let creases = ranges
16499            .into_iter()
16500            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16501            .collect();
16502
16503        self.fold_creases(creases, true, window, cx);
16504    }
16505
16506    pub fn fold_recursive(
16507        &mut self,
16508        _: &actions::FoldRecursive,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) {
16512        let mut to_fold = Vec::new();
16513        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16514        let selections = self.selections.all_adjusted(cx);
16515
16516        for selection in selections {
16517            let range = selection.range().sorted();
16518            let buffer_start_row = range.start.row;
16519
16520            if range.start.row != range.end.row {
16521                let mut found = false;
16522                for row in range.start.row..=range.end.row {
16523                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16524                        found = true;
16525                        to_fold.push(crease);
16526                    }
16527                }
16528                if found {
16529                    continue;
16530                }
16531            }
16532
16533            for row in (0..=range.start.row).rev() {
16534                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16535                    if crease.range().end.row >= buffer_start_row {
16536                        to_fold.push(crease);
16537                    } else {
16538                        break;
16539                    }
16540                }
16541            }
16542        }
16543
16544        self.fold_creases(to_fold, true, window, cx);
16545    }
16546
16547    pub fn fold_at(
16548        &mut self,
16549        buffer_row: MultiBufferRow,
16550        window: &mut Window,
16551        cx: &mut Context<Self>,
16552    ) {
16553        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16554
16555        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16556            let autoscroll = self
16557                .selections
16558                .all::<Point>(cx)
16559                .iter()
16560                .any(|selection| crease.range().overlaps(&selection.range()));
16561
16562            self.fold_creases(vec![crease], autoscroll, window, cx);
16563        }
16564    }
16565
16566    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16567        if self.is_singleton(cx) {
16568            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16569            let buffer = &display_map.buffer_snapshot;
16570            let selections = self.selections.all::<Point>(cx);
16571            let ranges = selections
16572                .iter()
16573                .map(|s| {
16574                    let range = s.display_range(&display_map).sorted();
16575                    let mut start = range.start.to_point(&display_map);
16576                    let mut end = range.end.to_point(&display_map);
16577                    start.column = 0;
16578                    end.column = buffer.line_len(MultiBufferRow(end.row));
16579                    start..end
16580                })
16581                .collect::<Vec<_>>();
16582
16583            self.unfold_ranges(&ranges, true, true, cx);
16584        } else {
16585            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16586            let buffer_ids = self
16587                .selections
16588                .disjoint_anchor_ranges()
16589                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16590                .collect::<HashSet<_>>();
16591            for buffer_id in buffer_ids {
16592                self.unfold_buffer(buffer_id, cx);
16593            }
16594        }
16595    }
16596
16597    pub fn unfold_recursive(
16598        &mut self,
16599        _: &UnfoldRecursive,
16600        _window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16604        let selections = self.selections.all::<Point>(cx);
16605        let ranges = selections
16606            .iter()
16607            .map(|s| {
16608                let mut range = s.display_range(&display_map).sorted();
16609                *range.start.column_mut() = 0;
16610                *range.end.column_mut() = display_map.line_len(range.end.row());
16611                let start = range.start.to_point(&display_map);
16612                let end = range.end.to_point(&display_map);
16613                start..end
16614            })
16615            .collect::<Vec<_>>();
16616
16617        self.unfold_ranges(&ranges, true, true, cx);
16618    }
16619
16620    pub fn unfold_at(
16621        &mut self,
16622        buffer_row: MultiBufferRow,
16623        _window: &mut Window,
16624        cx: &mut Context<Self>,
16625    ) {
16626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16627
16628        let intersection_range = Point::new(buffer_row.0, 0)
16629            ..Point::new(
16630                buffer_row.0,
16631                display_map.buffer_snapshot.line_len(buffer_row),
16632            );
16633
16634        let autoscroll = self
16635            .selections
16636            .all::<Point>(cx)
16637            .iter()
16638            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16639
16640        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16641    }
16642
16643    pub fn unfold_all(
16644        &mut self,
16645        _: &actions::UnfoldAll,
16646        _window: &mut Window,
16647        cx: &mut Context<Self>,
16648    ) {
16649        if self.buffer.read(cx).is_singleton() {
16650            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16651            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16652        } else {
16653            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16654                editor
16655                    .update(cx, |editor, cx| {
16656                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16657                            editor.unfold_buffer(buffer_id, cx);
16658                        }
16659                    })
16660                    .ok();
16661            });
16662        }
16663    }
16664
16665    pub fn fold_selected_ranges(
16666        &mut self,
16667        _: &FoldSelectedRanges,
16668        window: &mut Window,
16669        cx: &mut Context<Self>,
16670    ) {
16671        let selections = self.selections.all_adjusted(cx);
16672        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16673        let ranges = selections
16674            .into_iter()
16675            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16676            .collect::<Vec<_>>();
16677        self.fold_creases(ranges, true, window, cx);
16678    }
16679
16680    pub fn fold_ranges<T: ToOffset + Clone>(
16681        &mut self,
16682        ranges: Vec<Range<T>>,
16683        auto_scroll: bool,
16684        window: &mut Window,
16685        cx: &mut Context<Self>,
16686    ) {
16687        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16688        let ranges = ranges
16689            .into_iter()
16690            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16691            .collect::<Vec<_>>();
16692        self.fold_creases(ranges, auto_scroll, window, cx);
16693    }
16694
16695    pub fn fold_creases<T: ToOffset + Clone>(
16696        &mut self,
16697        creases: Vec<Crease<T>>,
16698        auto_scroll: bool,
16699        _window: &mut Window,
16700        cx: &mut Context<Self>,
16701    ) {
16702        if creases.is_empty() {
16703            return;
16704        }
16705
16706        let mut buffers_affected = HashSet::default();
16707        let multi_buffer = self.buffer().read(cx);
16708        for crease in &creases {
16709            if let Some((_, buffer, _)) =
16710                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16711            {
16712                buffers_affected.insert(buffer.read(cx).remote_id());
16713            };
16714        }
16715
16716        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16717
16718        if auto_scroll {
16719            self.request_autoscroll(Autoscroll::fit(), cx);
16720        }
16721
16722        cx.notify();
16723
16724        self.scrollbar_marker_state.dirty = true;
16725        self.folds_did_change(cx);
16726    }
16727
16728    /// Removes any folds whose ranges intersect any of the given ranges.
16729    pub fn unfold_ranges<T: ToOffset + Clone>(
16730        &mut self,
16731        ranges: &[Range<T>],
16732        inclusive: bool,
16733        auto_scroll: bool,
16734        cx: &mut Context<Self>,
16735    ) {
16736        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16737            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16738        });
16739        self.folds_did_change(cx);
16740    }
16741
16742    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16743        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16744            return;
16745        }
16746        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16747        self.display_map.update(cx, |display_map, cx| {
16748            display_map.fold_buffers([buffer_id], cx)
16749        });
16750        cx.emit(EditorEvent::BufferFoldToggled {
16751            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16752            folded: true,
16753        });
16754        cx.notify();
16755    }
16756
16757    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16758        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16759            return;
16760        }
16761        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16762        self.display_map.update(cx, |display_map, cx| {
16763            display_map.unfold_buffers([buffer_id], cx);
16764        });
16765        cx.emit(EditorEvent::BufferFoldToggled {
16766            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16767            folded: false,
16768        });
16769        cx.notify();
16770    }
16771
16772    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16773        self.display_map.read(cx).is_buffer_folded(buffer)
16774    }
16775
16776    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16777        self.display_map.read(cx).folded_buffers()
16778    }
16779
16780    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16781        self.display_map.update(cx, |display_map, cx| {
16782            display_map.disable_header_for_buffer(buffer_id, cx);
16783        });
16784        cx.notify();
16785    }
16786
16787    /// Removes any folds with the given ranges.
16788    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16789        &mut self,
16790        ranges: &[Range<T>],
16791        type_id: TypeId,
16792        auto_scroll: bool,
16793        cx: &mut Context<Self>,
16794    ) {
16795        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16796            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16797        });
16798        self.folds_did_change(cx);
16799    }
16800
16801    fn remove_folds_with<T: ToOffset + Clone>(
16802        &mut self,
16803        ranges: &[Range<T>],
16804        auto_scroll: bool,
16805        cx: &mut Context<Self>,
16806        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16807    ) {
16808        if ranges.is_empty() {
16809            return;
16810        }
16811
16812        let mut buffers_affected = HashSet::default();
16813        let multi_buffer = self.buffer().read(cx);
16814        for range in ranges {
16815            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16816                buffers_affected.insert(buffer.read(cx).remote_id());
16817            };
16818        }
16819
16820        self.display_map.update(cx, update);
16821
16822        if auto_scroll {
16823            self.request_autoscroll(Autoscroll::fit(), cx);
16824        }
16825
16826        cx.notify();
16827        self.scrollbar_marker_state.dirty = true;
16828        self.active_indent_guides_state.dirty = true;
16829    }
16830
16831    pub fn update_fold_widths(
16832        &mut self,
16833        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16834        cx: &mut Context<Self>,
16835    ) -> bool {
16836        self.display_map
16837            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16838    }
16839
16840    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16841        self.display_map.read(cx).fold_placeholder.clone()
16842    }
16843
16844    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16845        self.buffer.update(cx, |buffer, cx| {
16846            buffer.set_all_diff_hunks_expanded(cx);
16847        });
16848    }
16849
16850    pub fn expand_all_diff_hunks(
16851        &mut self,
16852        _: &ExpandAllDiffHunks,
16853        _window: &mut Window,
16854        cx: &mut Context<Self>,
16855    ) {
16856        self.buffer.update(cx, |buffer, cx| {
16857            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16858        });
16859    }
16860
16861    pub fn toggle_selected_diff_hunks(
16862        &mut self,
16863        _: &ToggleSelectedDiffHunks,
16864        _window: &mut Window,
16865        cx: &mut Context<Self>,
16866    ) {
16867        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16868        self.toggle_diff_hunks_in_ranges(ranges, cx);
16869    }
16870
16871    pub fn diff_hunks_in_ranges<'a>(
16872        &'a self,
16873        ranges: &'a [Range<Anchor>],
16874        buffer: &'a MultiBufferSnapshot,
16875    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16876        ranges.iter().flat_map(move |range| {
16877            let end_excerpt_id = range.end.excerpt_id;
16878            let range = range.to_point(buffer);
16879            let mut peek_end = range.end;
16880            if range.end.row < buffer.max_row().0 {
16881                peek_end = Point::new(range.end.row + 1, 0);
16882            }
16883            buffer
16884                .diff_hunks_in_range(range.start..peek_end)
16885                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16886        })
16887    }
16888
16889    pub fn has_stageable_diff_hunks_in_ranges(
16890        &self,
16891        ranges: &[Range<Anchor>],
16892        snapshot: &MultiBufferSnapshot,
16893    ) -> bool {
16894        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16895        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16896    }
16897
16898    pub fn toggle_staged_selected_diff_hunks(
16899        &mut self,
16900        _: &::git::ToggleStaged,
16901        _: &mut Window,
16902        cx: &mut Context<Self>,
16903    ) {
16904        let snapshot = self.buffer.read(cx).snapshot(cx);
16905        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16906        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16907        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16908    }
16909
16910    pub fn set_render_diff_hunk_controls(
16911        &mut self,
16912        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16913        cx: &mut Context<Self>,
16914    ) {
16915        self.render_diff_hunk_controls = render_diff_hunk_controls;
16916        cx.notify();
16917    }
16918
16919    pub fn stage_and_next(
16920        &mut self,
16921        _: &::git::StageAndNext,
16922        window: &mut Window,
16923        cx: &mut Context<Self>,
16924    ) {
16925        self.do_stage_or_unstage_and_next(true, window, cx);
16926    }
16927
16928    pub fn unstage_and_next(
16929        &mut self,
16930        _: &::git::UnstageAndNext,
16931        window: &mut Window,
16932        cx: &mut Context<Self>,
16933    ) {
16934        self.do_stage_or_unstage_and_next(false, window, cx);
16935    }
16936
16937    pub fn stage_or_unstage_diff_hunks(
16938        &mut self,
16939        stage: bool,
16940        ranges: Vec<Range<Anchor>>,
16941        cx: &mut Context<Self>,
16942    ) {
16943        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16944        cx.spawn(async move |this, cx| {
16945            task.await?;
16946            this.update(cx, |this, cx| {
16947                let snapshot = this.buffer.read(cx).snapshot(cx);
16948                let chunk_by = this
16949                    .diff_hunks_in_ranges(&ranges, &snapshot)
16950                    .chunk_by(|hunk| hunk.buffer_id);
16951                for (buffer_id, hunks) in &chunk_by {
16952                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16953                }
16954            })
16955        })
16956        .detach_and_log_err(cx);
16957    }
16958
16959    fn save_buffers_for_ranges_if_needed(
16960        &mut self,
16961        ranges: &[Range<Anchor>],
16962        cx: &mut Context<Editor>,
16963    ) -> Task<Result<()>> {
16964        let multibuffer = self.buffer.read(cx);
16965        let snapshot = multibuffer.read(cx);
16966        let buffer_ids: HashSet<_> = ranges
16967            .iter()
16968            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16969            .collect();
16970        drop(snapshot);
16971
16972        let mut buffers = HashSet::default();
16973        for buffer_id in buffer_ids {
16974            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16975                let buffer = buffer_entity.read(cx);
16976                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16977                {
16978                    buffers.insert(buffer_entity);
16979                }
16980            }
16981        }
16982
16983        if let Some(project) = &self.project {
16984            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16985        } else {
16986            Task::ready(Ok(()))
16987        }
16988    }
16989
16990    fn do_stage_or_unstage_and_next(
16991        &mut self,
16992        stage: bool,
16993        window: &mut Window,
16994        cx: &mut Context<Self>,
16995    ) {
16996        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16997
16998        if ranges.iter().any(|range| range.start != range.end) {
16999            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17000            return;
17001        }
17002
17003        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17004        let snapshot = self.snapshot(window, cx);
17005        let position = self.selections.newest::<Point>(cx).head();
17006        let mut row = snapshot
17007            .buffer_snapshot
17008            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17009            .find(|hunk| hunk.row_range.start.0 > position.row)
17010            .map(|hunk| hunk.row_range.start);
17011
17012        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17013        // Outside of the project diff editor, wrap around to the beginning.
17014        if !all_diff_hunks_expanded {
17015            row = row.or_else(|| {
17016                snapshot
17017                    .buffer_snapshot
17018                    .diff_hunks_in_range(Point::zero()..position)
17019                    .find(|hunk| hunk.row_range.end.0 < position.row)
17020                    .map(|hunk| hunk.row_range.start)
17021            });
17022        }
17023
17024        if let Some(row) = row {
17025            let destination = Point::new(row.0, 0);
17026            let autoscroll = Autoscroll::center();
17027
17028            self.unfold_ranges(&[destination..destination], false, false, cx);
17029            self.change_selections(Some(autoscroll), window, cx, |s| {
17030                s.select_ranges([destination..destination]);
17031            });
17032        }
17033    }
17034
17035    fn do_stage_or_unstage(
17036        &self,
17037        stage: bool,
17038        buffer_id: BufferId,
17039        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17040        cx: &mut App,
17041    ) -> Option<()> {
17042        let project = self.project.as_ref()?;
17043        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17044        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17045        let buffer_snapshot = buffer.read(cx).snapshot();
17046        let file_exists = buffer_snapshot
17047            .file()
17048            .is_some_and(|file| file.disk_state().exists());
17049        diff.update(cx, |diff, cx| {
17050            diff.stage_or_unstage_hunks(
17051                stage,
17052                &hunks
17053                    .map(|hunk| buffer_diff::DiffHunk {
17054                        buffer_range: hunk.buffer_range,
17055                        diff_base_byte_range: hunk.diff_base_byte_range,
17056                        secondary_status: hunk.secondary_status,
17057                        range: Point::zero()..Point::zero(), // unused
17058                    })
17059                    .collect::<Vec<_>>(),
17060                &buffer_snapshot,
17061                file_exists,
17062                cx,
17063            )
17064        });
17065        None
17066    }
17067
17068    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17069        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17070        self.buffer
17071            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17072    }
17073
17074    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17075        self.buffer.update(cx, |buffer, cx| {
17076            let ranges = vec![Anchor::min()..Anchor::max()];
17077            if !buffer.all_diff_hunks_expanded()
17078                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17079            {
17080                buffer.collapse_diff_hunks(ranges, cx);
17081                true
17082            } else {
17083                false
17084            }
17085        })
17086    }
17087
17088    fn toggle_diff_hunks_in_ranges(
17089        &mut self,
17090        ranges: Vec<Range<Anchor>>,
17091        cx: &mut Context<Editor>,
17092    ) {
17093        self.buffer.update(cx, |buffer, cx| {
17094            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17095            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17096        })
17097    }
17098
17099    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17100        self.buffer.update(cx, |buffer, cx| {
17101            let snapshot = buffer.snapshot(cx);
17102            let excerpt_id = range.end.excerpt_id;
17103            let point_range = range.to_point(&snapshot);
17104            let expand = !buffer.single_hunk_is_expanded(range, cx);
17105            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17106        })
17107    }
17108
17109    pub(crate) fn apply_all_diff_hunks(
17110        &mut self,
17111        _: &ApplyAllDiffHunks,
17112        window: &mut Window,
17113        cx: &mut Context<Self>,
17114    ) {
17115        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17116
17117        let buffers = self.buffer.read(cx).all_buffers();
17118        for branch_buffer in buffers {
17119            branch_buffer.update(cx, |branch_buffer, cx| {
17120                branch_buffer.merge_into_base(Vec::new(), cx);
17121            });
17122        }
17123
17124        if let Some(project) = self.project.clone() {
17125            self.save(
17126                SaveOptions {
17127                    format: true,
17128                    autosave: false,
17129                },
17130                project,
17131                window,
17132                cx,
17133            )
17134            .detach_and_log_err(cx);
17135        }
17136    }
17137
17138    pub(crate) fn apply_selected_diff_hunks(
17139        &mut self,
17140        _: &ApplyDiffHunk,
17141        window: &mut Window,
17142        cx: &mut Context<Self>,
17143    ) {
17144        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17145        let snapshot = self.snapshot(window, cx);
17146        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17147        let mut ranges_by_buffer = HashMap::default();
17148        self.transact(window, cx, |editor, _window, cx| {
17149            for hunk in hunks {
17150                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17151                    ranges_by_buffer
17152                        .entry(buffer.clone())
17153                        .or_insert_with(Vec::new)
17154                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17155                }
17156            }
17157
17158            for (buffer, ranges) in ranges_by_buffer {
17159                buffer.update(cx, |buffer, cx| {
17160                    buffer.merge_into_base(ranges, cx);
17161                });
17162            }
17163        });
17164
17165        if let Some(project) = self.project.clone() {
17166            self.save(
17167                SaveOptions {
17168                    format: true,
17169                    autosave: false,
17170                },
17171                project,
17172                window,
17173                cx,
17174            )
17175            .detach_and_log_err(cx);
17176        }
17177    }
17178
17179    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17180        if hovered != self.gutter_hovered {
17181            self.gutter_hovered = hovered;
17182            cx.notify();
17183        }
17184    }
17185
17186    pub fn insert_blocks(
17187        &mut self,
17188        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17189        autoscroll: Option<Autoscroll>,
17190        cx: &mut Context<Self>,
17191    ) -> Vec<CustomBlockId> {
17192        let blocks = self
17193            .display_map
17194            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17195        if let Some(autoscroll) = autoscroll {
17196            self.request_autoscroll(autoscroll, cx);
17197        }
17198        cx.notify();
17199        blocks
17200    }
17201
17202    pub fn resize_blocks(
17203        &mut self,
17204        heights: HashMap<CustomBlockId, u32>,
17205        autoscroll: Option<Autoscroll>,
17206        cx: &mut Context<Self>,
17207    ) {
17208        self.display_map
17209            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17210        if let Some(autoscroll) = autoscroll {
17211            self.request_autoscroll(autoscroll, cx);
17212        }
17213        cx.notify();
17214    }
17215
17216    pub fn replace_blocks(
17217        &mut self,
17218        renderers: HashMap<CustomBlockId, RenderBlock>,
17219        autoscroll: Option<Autoscroll>,
17220        cx: &mut Context<Self>,
17221    ) {
17222        self.display_map
17223            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17224        if let Some(autoscroll) = autoscroll {
17225            self.request_autoscroll(autoscroll, cx);
17226        }
17227        cx.notify();
17228    }
17229
17230    pub fn remove_blocks(
17231        &mut self,
17232        block_ids: HashSet<CustomBlockId>,
17233        autoscroll: Option<Autoscroll>,
17234        cx: &mut Context<Self>,
17235    ) {
17236        self.display_map.update(cx, |display_map, cx| {
17237            display_map.remove_blocks(block_ids, cx)
17238        });
17239        if let Some(autoscroll) = autoscroll {
17240            self.request_autoscroll(autoscroll, cx);
17241        }
17242        cx.notify();
17243    }
17244
17245    pub fn row_for_block(
17246        &self,
17247        block_id: CustomBlockId,
17248        cx: &mut Context<Self>,
17249    ) -> Option<DisplayRow> {
17250        self.display_map
17251            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17252    }
17253
17254    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17255        self.focused_block = Some(focused_block);
17256    }
17257
17258    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17259        self.focused_block.take()
17260    }
17261
17262    pub fn insert_creases(
17263        &mut self,
17264        creases: impl IntoIterator<Item = Crease<Anchor>>,
17265        cx: &mut Context<Self>,
17266    ) -> Vec<CreaseId> {
17267        self.display_map
17268            .update(cx, |map, cx| map.insert_creases(creases, cx))
17269    }
17270
17271    pub fn remove_creases(
17272        &mut self,
17273        ids: impl IntoIterator<Item = CreaseId>,
17274        cx: &mut Context<Self>,
17275    ) -> Vec<(CreaseId, Range<Anchor>)> {
17276        self.display_map
17277            .update(cx, |map, cx| map.remove_creases(ids, cx))
17278    }
17279
17280    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17281        self.display_map
17282            .update(cx, |map, cx| map.snapshot(cx))
17283            .longest_row()
17284    }
17285
17286    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17287        self.display_map
17288            .update(cx, |map, cx| map.snapshot(cx))
17289            .max_point()
17290    }
17291
17292    pub fn text(&self, cx: &App) -> String {
17293        self.buffer.read(cx).read(cx).text()
17294    }
17295
17296    pub fn is_empty(&self, cx: &App) -> bool {
17297        self.buffer.read(cx).read(cx).is_empty()
17298    }
17299
17300    pub fn text_option(&self, cx: &App) -> Option<String> {
17301        let text = self.text(cx);
17302        let text = text.trim();
17303
17304        if text.is_empty() {
17305            return None;
17306        }
17307
17308        Some(text.to_string())
17309    }
17310
17311    pub fn set_text(
17312        &mut self,
17313        text: impl Into<Arc<str>>,
17314        window: &mut Window,
17315        cx: &mut Context<Self>,
17316    ) {
17317        self.transact(window, cx, |this, _, cx| {
17318            this.buffer
17319                .read(cx)
17320                .as_singleton()
17321                .expect("you can only call set_text on editors for singleton buffers")
17322                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17323        });
17324    }
17325
17326    pub fn display_text(&self, cx: &mut App) -> String {
17327        self.display_map
17328            .update(cx, |map, cx| map.snapshot(cx))
17329            .text()
17330    }
17331
17332    fn create_minimap(
17333        &self,
17334        minimap_settings: MinimapSettings,
17335        window: &mut Window,
17336        cx: &mut Context<Self>,
17337    ) -> Option<Entity<Self>> {
17338        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17339            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17340    }
17341
17342    fn initialize_new_minimap(
17343        &self,
17344        minimap_settings: MinimapSettings,
17345        window: &mut Window,
17346        cx: &mut Context<Self>,
17347    ) -> Entity<Self> {
17348        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17349
17350        let mut minimap = Editor::new_internal(
17351            EditorMode::Minimap {
17352                parent: cx.weak_entity(),
17353            },
17354            self.buffer.clone(),
17355            self.project.clone(),
17356            Some(self.display_map.clone()),
17357            window,
17358            cx,
17359        );
17360        minimap.scroll_manager.clone_state(&self.scroll_manager);
17361        minimap.set_text_style_refinement(TextStyleRefinement {
17362            font_size: Some(MINIMAP_FONT_SIZE),
17363            font_weight: Some(MINIMAP_FONT_WEIGHT),
17364            ..Default::default()
17365        });
17366        minimap.update_minimap_configuration(minimap_settings, cx);
17367        cx.new(|_| minimap)
17368    }
17369
17370    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17371        let current_line_highlight = minimap_settings
17372            .current_line_highlight
17373            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17374        self.set_current_line_highlight(Some(current_line_highlight));
17375    }
17376
17377    pub fn minimap(&self) -> Option<&Entity<Self>> {
17378        self.minimap
17379            .as_ref()
17380            .filter(|_| self.minimap_visibility.visible())
17381    }
17382
17383    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17384        let mut wrap_guides = smallvec![];
17385
17386        if self.show_wrap_guides == Some(false) {
17387            return wrap_guides;
17388        }
17389
17390        let settings = self.buffer.read(cx).language_settings(cx);
17391        if settings.show_wrap_guides {
17392            match self.soft_wrap_mode(cx) {
17393                SoftWrap::Column(soft_wrap) => {
17394                    wrap_guides.push((soft_wrap as usize, true));
17395                }
17396                SoftWrap::Bounded(soft_wrap) => {
17397                    wrap_guides.push((soft_wrap as usize, true));
17398                }
17399                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17400            }
17401            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17402        }
17403
17404        wrap_guides
17405    }
17406
17407    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17408        let settings = self.buffer.read(cx).language_settings(cx);
17409        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17410        match mode {
17411            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17412                SoftWrap::None
17413            }
17414            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17415            language_settings::SoftWrap::PreferredLineLength => {
17416                SoftWrap::Column(settings.preferred_line_length)
17417            }
17418            language_settings::SoftWrap::Bounded => {
17419                SoftWrap::Bounded(settings.preferred_line_length)
17420            }
17421        }
17422    }
17423
17424    pub fn set_soft_wrap_mode(
17425        &mut self,
17426        mode: language_settings::SoftWrap,
17427
17428        cx: &mut Context<Self>,
17429    ) {
17430        self.soft_wrap_mode_override = Some(mode);
17431        cx.notify();
17432    }
17433
17434    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17435        self.hard_wrap = hard_wrap;
17436        cx.notify();
17437    }
17438
17439    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17440        self.text_style_refinement = Some(style);
17441    }
17442
17443    /// called by the Element so we know what style we were most recently rendered with.
17444    pub(crate) fn set_style(
17445        &mut self,
17446        style: EditorStyle,
17447        window: &mut Window,
17448        cx: &mut Context<Self>,
17449    ) {
17450        // We intentionally do not inform the display map about the minimap style
17451        // so that wrapping is not recalculated and stays consistent for the editor
17452        // and its linked minimap.
17453        if !self.mode.is_minimap() {
17454            let rem_size = window.rem_size();
17455            self.display_map.update(cx, |map, cx| {
17456                map.set_font(
17457                    style.text.font(),
17458                    style.text.font_size.to_pixels(rem_size),
17459                    cx,
17460                )
17461            });
17462        }
17463        self.style = Some(style);
17464    }
17465
17466    pub fn style(&self) -> Option<&EditorStyle> {
17467        self.style.as_ref()
17468    }
17469
17470    // Called by the element. This method is not designed to be called outside of the editor
17471    // element's layout code because it does not notify when rewrapping is computed synchronously.
17472    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17473        self.display_map
17474            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17475    }
17476
17477    pub fn set_soft_wrap(&mut self) {
17478        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17479    }
17480
17481    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17482        if self.soft_wrap_mode_override.is_some() {
17483            self.soft_wrap_mode_override.take();
17484        } else {
17485            let soft_wrap = match self.soft_wrap_mode(cx) {
17486                SoftWrap::GitDiff => return,
17487                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17488                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17489                    language_settings::SoftWrap::None
17490                }
17491            };
17492            self.soft_wrap_mode_override = Some(soft_wrap);
17493        }
17494        cx.notify();
17495    }
17496
17497    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17498        let Some(workspace) = self.workspace() else {
17499            return;
17500        };
17501        let fs = workspace.read(cx).app_state().fs.clone();
17502        let current_show = TabBarSettings::get_global(cx).show;
17503        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17504            setting.show = Some(!current_show);
17505        });
17506    }
17507
17508    pub fn toggle_indent_guides(
17509        &mut self,
17510        _: &ToggleIndentGuides,
17511        _: &mut Window,
17512        cx: &mut Context<Self>,
17513    ) {
17514        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17515            self.buffer
17516                .read(cx)
17517                .language_settings(cx)
17518                .indent_guides
17519                .enabled
17520        });
17521        self.show_indent_guides = Some(!currently_enabled);
17522        cx.notify();
17523    }
17524
17525    fn should_show_indent_guides(&self) -> Option<bool> {
17526        self.show_indent_guides
17527    }
17528
17529    pub fn toggle_line_numbers(
17530        &mut self,
17531        _: &ToggleLineNumbers,
17532        _: &mut Window,
17533        cx: &mut Context<Self>,
17534    ) {
17535        let mut editor_settings = EditorSettings::get_global(cx).clone();
17536        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17537        EditorSettings::override_global(editor_settings, cx);
17538    }
17539
17540    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17541        if let Some(show_line_numbers) = self.show_line_numbers {
17542            return show_line_numbers;
17543        }
17544        EditorSettings::get_global(cx).gutter.line_numbers
17545    }
17546
17547    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17548        self.use_relative_line_numbers
17549            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17550    }
17551
17552    pub fn toggle_relative_line_numbers(
17553        &mut self,
17554        _: &ToggleRelativeLineNumbers,
17555        _: &mut Window,
17556        cx: &mut Context<Self>,
17557    ) {
17558        let is_relative = self.should_use_relative_line_numbers(cx);
17559        self.set_relative_line_number(Some(!is_relative), cx)
17560    }
17561
17562    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17563        self.use_relative_line_numbers = is_relative;
17564        cx.notify();
17565    }
17566
17567    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17568        self.show_gutter = show_gutter;
17569        cx.notify();
17570    }
17571
17572    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17573        self.show_scrollbars = ScrollbarAxes {
17574            horizontal: show,
17575            vertical: show,
17576        };
17577        cx.notify();
17578    }
17579
17580    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17581        self.show_scrollbars.vertical = show;
17582        cx.notify();
17583    }
17584
17585    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17586        self.show_scrollbars.horizontal = show;
17587        cx.notify();
17588    }
17589
17590    pub fn set_minimap_visibility(
17591        &mut self,
17592        minimap_visibility: MinimapVisibility,
17593        window: &mut Window,
17594        cx: &mut Context<Self>,
17595    ) {
17596        if self.minimap_visibility != minimap_visibility {
17597            if minimap_visibility.visible() && self.minimap.is_none() {
17598                let minimap_settings = EditorSettings::get_global(cx).minimap;
17599                self.minimap =
17600                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17601            }
17602            self.minimap_visibility = minimap_visibility;
17603            cx.notify();
17604        }
17605    }
17606
17607    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17608        self.set_show_scrollbars(false, cx);
17609        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17610    }
17611
17612    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17613        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17614    }
17615
17616    /// Normally the text in full mode and auto height editors is padded on the
17617    /// left side by roughly half a character width for improved hit testing.
17618    ///
17619    /// Use this method to disable this for cases where this is not wanted (e.g.
17620    /// if you want to align the editor text with some other text above or below)
17621    /// or if you want to add this padding to single-line editors.
17622    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17623        self.offset_content = offset_content;
17624        cx.notify();
17625    }
17626
17627    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17628        self.show_line_numbers = Some(show_line_numbers);
17629        cx.notify();
17630    }
17631
17632    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17633        self.disable_expand_excerpt_buttons = true;
17634        cx.notify();
17635    }
17636
17637    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17638        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17639        cx.notify();
17640    }
17641
17642    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17643        self.show_code_actions = Some(show_code_actions);
17644        cx.notify();
17645    }
17646
17647    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17648        self.show_runnables = Some(show_runnables);
17649        cx.notify();
17650    }
17651
17652    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17653        self.show_breakpoints = Some(show_breakpoints);
17654        cx.notify();
17655    }
17656
17657    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17658        if self.display_map.read(cx).masked != masked {
17659            self.display_map.update(cx, |map, _| map.masked = masked);
17660        }
17661        cx.notify()
17662    }
17663
17664    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17665        self.show_wrap_guides = Some(show_wrap_guides);
17666        cx.notify();
17667    }
17668
17669    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17670        self.show_indent_guides = Some(show_indent_guides);
17671        cx.notify();
17672    }
17673
17674    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17675        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17676            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17677                if let Some(dir) = file.abs_path(cx).parent() {
17678                    return Some(dir.to_owned());
17679                }
17680            }
17681
17682            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17683                return Some(project_path.path.to_path_buf());
17684            }
17685        }
17686
17687        None
17688    }
17689
17690    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17691        self.active_excerpt(cx)?
17692            .1
17693            .read(cx)
17694            .file()
17695            .and_then(|f| f.as_local())
17696    }
17697
17698    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17699        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17700            let buffer = buffer.read(cx);
17701            if let Some(project_path) = buffer.project_path(cx) {
17702                let project = self.project.as_ref()?.read(cx);
17703                project.absolute_path(&project_path, cx)
17704            } else {
17705                buffer
17706                    .file()
17707                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17708            }
17709        })
17710    }
17711
17712    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17713        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17714            let project_path = buffer.read(cx).project_path(cx)?;
17715            let project = self.project.as_ref()?.read(cx);
17716            let entry = project.entry_for_path(&project_path, cx)?;
17717            let path = entry.path.to_path_buf();
17718            Some(path)
17719        })
17720    }
17721
17722    pub fn reveal_in_finder(
17723        &mut self,
17724        _: &RevealInFileManager,
17725        _window: &mut Window,
17726        cx: &mut Context<Self>,
17727    ) {
17728        if let Some(target) = self.target_file(cx) {
17729            cx.reveal_path(&target.abs_path(cx));
17730        }
17731    }
17732
17733    pub fn copy_path(
17734        &mut self,
17735        _: &zed_actions::workspace::CopyPath,
17736        _window: &mut Window,
17737        cx: &mut Context<Self>,
17738    ) {
17739        if let Some(path) = self.target_file_abs_path(cx) {
17740            if let Some(path) = path.to_str() {
17741                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17742            }
17743        }
17744    }
17745
17746    pub fn copy_relative_path(
17747        &mut self,
17748        _: &zed_actions::workspace::CopyRelativePath,
17749        _window: &mut Window,
17750        cx: &mut Context<Self>,
17751    ) {
17752        if let Some(path) = self.target_file_path(cx) {
17753            if let Some(path) = path.to_str() {
17754                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17755            }
17756        }
17757    }
17758
17759    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17760        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17761            buffer.read(cx).project_path(cx)
17762        } else {
17763            None
17764        }
17765    }
17766
17767    // Returns true if the editor handled a go-to-line request
17768    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17769        maybe!({
17770            let breakpoint_store = self.breakpoint_store.as_ref()?;
17771
17772            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17773            else {
17774                self.clear_row_highlights::<ActiveDebugLine>();
17775                return None;
17776            };
17777
17778            let position = active_stack_frame.position;
17779            let buffer_id = position.buffer_id?;
17780            let snapshot = self
17781                .project
17782                .as_ref()?
17783                .read(cx)
17784                .buffer_for_id(buffer_id, cx)?
17785                .read(cx)
17786                .snapshot();
17787
17788            let mut handled = false;
17789            for (id, ExcerptRange { context, .. }) in
17790                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17791            {
17792                if context.start.cmp(&position, &snapshot).is_ge()
17793                    || context.end.cmp(&position, &snapshot).is_lt()
17794                {
17795                    continue;
17796                }
17797                let snapshot = self.buffer.read(cx).snapshot(cx);
17798                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17799
17800                handled = true;
17801                self.clear_row_highlights::<ActiveDebugLine>();
17802
17803                self.go_to_line::<ActiveDebugLine>(
17804                    multibuffer_anchor,
17805                    Some(cx.theme().colors().editor_debugger_active_line_background),
17806                    window,
17807                    cx,
17808                );
17809
17810                cx.notify();
17811            }
17812
17813            handled.then_some(())
17814        })
17815        .is_some()
17816    }
17817
17818    pub fn copy_file_name_without_extension(
17819        &mut self,
17820        _: &CopyFileNameWithoutExtension,
17821        _: &mut Window,
17822        cx: &mut Context<Self>,
17823    ) {
17824        if let Some(file) = self.target_file(cx) {
17825            if let Some(file_stem) = file.path().file_stem() {
17826                if let Some(name) = file_stem.to_str() {
17827                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17828                }
17829            }
17830        }
17831    }
17832
17833    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17834        if let Some(file) = self.target_file(cx) {
17835            if let Some(file_name) = file.path().file_name() {
17836                if let Some(name) = file_name.to_str() {
17837                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17838                }
17839            }
17840        }
17841    }
17842
17843    pub fn toggle_git_blame(
17844        &mut self,
17845        _: &::git::Blame,
17846        window: &mut Window,
17847        cx: &mut Context<Self>,
17848    ) {
17849        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17850
17851        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17852            self.start_git_blame(true, window, cx);
17853        }
17854
17855        cx.notify();
17856    }
17857
17858    pub fn toggle_git_blame_inline(
17859        &mut self,
17860        _: &ToggleGitBlameInline,
17861        window: &mut Window,
17862        cx: &mut Context<Self>,
17863    ) {
17864        self.toggle_git_blame_inline_internal(true, window, cx);
17865        cx.notify();
17866    }
17867
17868    pub fn open_git_blame_commit(
17869        &mut self,
17870        _: &OpenGitBlameCommit,
17871        window: &mut Window,
17872        cx: &mut Context<Self>,
17873    ) {
17874        self.open_git_blame_commit_internal(window, cx);
17875    }
17876
17877    fn open_git_blame_commit_internal(
17878        &mut self,
17879        window: &mut Window,
17880        cx: &mut Context<Self>,
17881    ) -> Option<()> {
17882        let blame = self.blame.as_ref()?;
17883        let snapshot = self.snapshot(window, cx);
17884        let cursor = self.selections.newest::<Point>(cx).head();
17885        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17886        let blame_entry = blame
17887            .update(cx, |blame, cx| {
17888                blame
17889                    .blame_for_rows(
17890                        &[RowInfo {
17891                            buffer_id: Some(buffer.remote_id()),
17892                            buffer_row: Some(point.row),
17893                            ..Default::default()
17894                        }],
17895                        cx,
17896                    )
17897                    .next()
17898            })
17899            .flatten()?;
17900        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17901        let repo = blame.read(cx).repository(cx)?;
17902        let workspace = self.workspace()?.downgrade();
17903        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17904        None
17905    }
17906
17907    pub fn git_blame_inline_enabled(&self) -> bool {
17908        self.git_blame_inline_enabled
17909    }
17910
17911    pub fn toggle_selection_menu(
17912        &mut self,
17913        _: &ToggleSelectionMenu,
17914        _: &mut Window,
17915        cx: &mut Context<Self>,
17916    ) {
17917        self.show_selection_menu = self
17918            .show_selection_menu
17919            .map(|show_selections_menu| !show_selections_menu)
17920            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17921
17922        cx.notify();
17923    }
17924
17925    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17926        self.show_selection_menu
17927            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17928    }
17929
17930    fn start_git_blame(
17931        &mut self,
17932        user_triggered: bool,
17933        window: &mut Window,
17934        cx: &mut Context<Self>,
17935    ) {
17936        if let Some(project) = self.project.as_ref() {
17937            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17938                return;
17939            };
17940
17941            if buffer.read(cx).file().is_none() {
17942                return;
17943            }
17944
17945            let focused = self.focus_handle(cx).contains_focused(window, cx);
17946
17947            let project = project.clone();
17948            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17949            self.blame_subscription =
17950                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17951            self.blame = Some(blame);
17952        }
17953    }
17954
17955    fn toggle_git_blame_inline_internal(
17956        &mut self,
17957        user_triggered: bool,
17958        window: &mut Window,
17959        cx: &mut Context<Self>,
17960    ) {
17961        if self.git_blame_inline_enabled {
17962            self.git_blame_inline_enabled = false;
17963            self.show_git_blame_inline = false;
17964            self.show_git_blame_inline_delay_task.take();
17965        } else {
17966            self.git_blame_inline_enabled = true;
17967            self.start_git_blame_inline(user_triggered, window, cx);
17968        }
17969
17970        cx.notify();
17971    }
17972
17973    fn start_git_blame_inline(
17974        &mut self,
17975        user_triggered: bool,
17976        window: &mut Window,
17977        cx: &mut Context<Self>,
17978    ) {
17979        self.start_git_blame(user_triggered, window, cx);
17980
17981        if ProjectSettings::get_global(cx)
17982            .git
17983            .inline_blame_delay()
17984            .is_some()
17985        {
17986            self.start_inline_blame_timer(window, cx);
17987        } else {
17988            self.show_git_blame_inline = true
17989        }
17990    }
17991
17992    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17993        self.blame.as_ref()
17994    }
17995
17996    pub fn show_git_blame_gutter(&self) -> bool {
17997        self.show_git_blame_gutter
17998    }
17999
18000    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18001        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18002    }
18003
18004    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18005        self.show_git_blame_inline
18006            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18007            && !self.newest_selection_head_on_empty_line(cx)
18008            && self.has_blame_entries(cx)
18009    }
18010
18011    fn has_blame_entries(&self, cx: &App) -> bool {
18012        self.blame()
18013            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18014    }
18015
18016    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18017        let cursor_anchor = self.selections.newest_anchor().head();
18018
18019        let snapshot = self.buffer.read(cx).snapshot(cx);
18020        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18021
18022        snapshot.line_len(buffer_row) == 0
18023    }
18024
18025    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18026        let buffer_and_selection = maybe!({
18027            let selection = self.selections.newest::<Point>(cx);
18028            let selection_range = selection.range();
18029
18030            let multi_buffer = self.buffer().read(cx);
18031            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18032            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18033
18034            let (buffer, range, _) = if selection.reversed {
18035                buffer_ranges.first()
18036            } else {
18037                buffer_ranges.last()
18038            }?;
18039
18040            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18041                ..text::ToPoint::to_point(&range.end, &buffer).row;
18042            Some((
18043                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18044                selection,
18045            ))
18046        });
18047
18048        let Some((buffer, selection)) = buffer_and_selection else {
18049            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18050        };
18051
18052        let Some(project) = self.project.as_ref() else {
18053            return Task::ready(Err(anyhow!("editor does not have project")));
18054        };
18055
18056        project.update(cx, |project, cx| {
18057            project.get_permalink_to_line(&buffer, selection, cx)
18058        })
18059    }
18060
18061    pub fn copy_permalink_to_line(
18062        &mut self,
18063        _: &CopyPermalinkToLine,
18064        window: &mut Window,
18065        cx: &mut Context<Self>,
18066    ) {
18067        let permalink_task = self.get_permalink_to_line(cx);
18068        let workspace = self.workspace();
18069
18070        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18071            Ok(permalink) => {
18072                cx.update(|_, cx| {
18073                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18074                })
18075                .ok();
18076            }
18077            Err(err) => {
18078                let message = format!("Failed to copy permalink: {err}");
18079
18080                anyhow::Result::<()>::Err(err).log_err();
18081
18082                if let Some(workspace) = workspace {
18083                    workspace
18084                        .update_in(cx, |workspace, _, cx| {
18085                            struct CopyPermalinkToLine;
18086
18087                            workspace.show_toast(
18088                                Toast::new(
18089                                    NotificationId::unique::<CopyPermalinkToLine>(),
18090                                    message,
18091                                ),
18092                                cx,
18093                            )
18094                        })
18095                        .ok();
18096                }
18097            }
18098        })
18099        .detach();
18100    }
18101
18102    pub fn copy_file_location(
18103        &mut self,
18104        _: &CopyFileLocation,
18105        _: &mut Window,
18106        cx: &mut Context<Self>,
18107    ) {
18108        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18109        if let Some(file) = self.target_file(cx) {
18110            if let Some(path) = file.path().to_str() {
18111                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18112            }
18113        }
18114    }
18115
18116    pub fn open_permalink_to_line(
18117        &mut self,
18118        _: &OpenPermalinkToLine,
18119        window: &mut Window,
18120        cx: &mut Context<Self>,
18121    ) {
18122        let permalink_task = self.get_permalink_to_line(cx);
18123        let workspace = self.workspace();
18124
18125        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18126            Ok(permalink) => {
18127                cx.update(|_, cx| {
18128                    cx.open_url(permalink.as_ref());
18129                })
18130                .ok();
18131            }
18132            Err(err) => {
18133                let message = format!("Failed to open permalink: {err}");
18134
18135                anyhow::Result::<()>::Err(err).log_err();
18136
18137                if let Some(workspace) = workspace {
18138                    workspace
18139                        .update(cx, |workspace, cx| {
18140                            struct OpenPermalinkToLine;
18141
18142                            workspace.show_toast(
18143                                Toast::new(
18144                                    NotificationId::unique::<OpenPermalinkToLine>(),
18145                                    message,
18146                                ),
18147                                cx,
18148                            )
18149                        })
18150                        .ok();
18151                }
18152            }
18153        })
18154        .detach();
18155    }
18156
18157    pub fn insert_uuid_v4(
18158        &mut self,
18159        _: &InsertUuidV4,
18160        window: &mut Window,
18161        cx: &mut Context<Self>,
18162    ) {
18163        self.insert_uuid(UuidVersion::V4, window, cx);
18164    }
18165
18166    pub fn insert_uuid_v7(
18167        &mut self,
18168        _: &InsertUuidV7,
18169        window: &mut Window,
18170        cx: &mut Context<Self>,
18171    ) {
18172        self.insert_uuid(UuidVersion::V7, window, cx);
18173    }
18174
18175    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18176        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18177        self.transact(window, cx, |this, window, cx| {
18178            let edits = this
18179                .selections
18180                .all::<Point>(cx)
18181                .into_iter()
18182                .map(|selection| {
18183                    let uuid = match version {
18184                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18185                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18186                    };
18187
18188                    (selection.range(), uuid.to_string())
18189                });
18190            this.edit(edits, cx);
18191            this.refresh_inline_completion(true, false, window, cx);
18192        });
18193    }
18194
18195    pub fn open_selections_in_multibuffer(
18196        &mut self,
18197        _: &OpenSelectionsInMultibuffer,
18198        window: &mut Window,
18199        cx: &mut Context<Self>,
18200    ) {
18201        let multibuffer = self.buffer.read(cx);
18202
18203        let Some(buffer) = multibuffer.as_singleton() else {
18204            return;
18205        };
18206
18207        let Some(workspace) = self.workspace() else {
18208            return;
18209        };
18210
18211        let locations = self
18212            .selections
18213            .disjoint_anchors()
18214            .iter()
18215            .map(|range| Location {
18216                buffer: buffer.clone(),
18217                range: range.start.text_anchor..range.end.text_anchor,
18218            })
18219            .collect::<Vec<_>>();
18220
18221        let title = multibuffer.title(cx).to_string();
18222
18223        cx.spawn_in(window, async move |_, cx| {
18224            workspace.update_in(cx, |workspace, window, cx| {
18225                Self::open_locations_in_multibuffer(
18226                    workspace,
18227                    locations,
18228                    format!("Selections for '{title}'"),
18229                    false,
18230                    MultibufferSelectionMode::All,
18231                    window,
18232                    cx,
18233                );
18234            })
18235        })
18236        .detach();
18237    }
18238
18239    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18240    /// last highlight added will be used.
18241    ///
18242    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18243    pub fn highlight_rows<T: 'static>(
18244        &mut self,
18245        range: Range<Anchor>,
18246        color: Hsla,
18247        options: RowHighlightOptions,
18248        cx: &mut Context<Self>,
18249    ) {
18250        let snapshot = self.buffer().read(cx).snapshot(cx);
18251        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18252        let ix = row_highlights.binary_search_by(|highlight| {
18253            Ordering::Equal
18254                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18255                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18256        });
18257
18258        if let Err(mut ix) = ix {
18259            let index = post_inc(&mut self.highlight_order);
18260
18261            // If this range intersects with the preceding highlight, then merge it with
18262            // the preceding highlight. Otherwise insert a new highlight.
18263            let mut merged = false;
18264            if ix > 0 {
18265                let prev_highlight = &mut row_highlights[ix - 1];
18266                if prev_highlight
18267                    .range
18268                    .end
18269                    .cmp(&range.start, &snapshot)
18270                    .is_ge()
18271                {
18272                    ix -= 1;
18273                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18274                        prev_highlight.range.end = range.end;
18275                    }
18276                    merged = true;
18277                    prev_highlight.index = index;
18278                    prev_highlight.color = color;
18279                    prev_highlight.options = options;
18280                }
18281            }
18282
18283            if !merged {
18284                row_highlights.insert(
18285                    ix,
18286                    RowHighlight {
18287                        range: range.clone(),
18288                        index,
18289                        color,
18290                        options,
18291                        type_id: TypeId::of::<T>(),
18292                    },
18293                );
18294            }
18295
18296            // If any of the following highlights intersect with this one, merge them.
18297            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18298                let highlight = &row_highlights[ix];
18299                if next_highlight
18300                    .range
18301                    .start
18302                    .cmp(&highlight.range.end, &snapshot)
18303                    .is_le()
18304                {
18305                    if next_highlight
18306                        .range
18307                        .end
18308                        .cmp(&highlight.range.end, &snapshot)
18309                        .is_gt()
18310                    {
18311                        row_highlights[ix].range.end = next_highlight.range.end;
18312                    }
18313                    row_highlights.remove(ix + 1);
18314                } else {
18315                    break;
18316                }
18317            }
18318        }
18319    }
18320
18321    /// Remove any highlighted row ranges of the given type that intersect the
18322    /// given ranges.
18323    pub fn remove_highlighted_rows<T: 'static>(
18324        &mut self,
18325        ranges_to_remove: Vec<Range<Anchor>>,
18326        cx: &mut Context<Self>,
18327    ) {
18328        let snapshot = self.buffer().read(cx).snapshot(cx);
18329        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18330        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18331        row_highlights.retain(|highlight| {
18332            while let Some(range_to_remove) = ranges_to_remove.peek() {
18333                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18334                    Ordering::Less | Ordering::Equal => {
18335                        ranges_to_remove.next();
18336                    }
18337                    Ordering::Greater => {
18338                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18339                            Ordering::Less | Ordering::Equal => {
18340                                return false;
18341                            }
18342                            Ordering::Greater => break,
18343                        }
18344                    }
18345                }
18346            }
18347
18348            true
18349        })
18350    }
18351
18352    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18353    pub fn clear_row_highlights<T: 'static>(&mut self) {
18354        self.highlighted_rows.remove(&TypeId::of::<T>());
18355    }
18356
18357    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18358    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18359        self.highlighted_rows
18360            .get(&TypeId::of::<T>())
18361            .map_or(&[] as &[_], |vec| vec.as_slice())
18362            .iter()
18363            .map(|highlight| (highlight.range.clone(), highlight.color))
18364    }
18365
18366    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18367    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18368    /// Allows to ignore certain kinds of highlights.
18369    pub fn highlighted_display_rows(
18370        &self,
18371        window: &mut Window,
18372        cx: &mut App,
18373    ) -> BTreeMap<DisplayRow, LineHighlight> {
18374        let snapshot = self.snapshot(window, cx);
18375        let mut used_highlight_orders = HashMap::default();
18376        self.highlighted_rows
18377            .iter()
18378            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18379            .fold(
18380                BTreeMap::<DisplayRow, LineHighlight>::new(),
18381                |mut unique_rows, highlight| {
18382                    let start = highlight.range.start.to_display_point(&snapshot);
18383                    let end = highlight.range.end.to_display_point(&snapshot);
18384                    let start_row = start.row().0;
18385                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18386                        && end.column() == 0
18387                    {
18388                        end.row().0.saturating_sub(1)
18389                    } else {
18390                        end.row().0
18391                    };
18392                    for row in start_row..=end_row {
18393                        let used_index =
18394                            used_highlight_orders.entry(row).or_insert(highlight.index);
18395                        if highlight.index >= *used_index {
18396                            *used_index = highlight.index;
18397                            unique_rows.insert(
18398                                DisplayRow(row),
18399                                LineHighlight {
18400                                    include_gutter: highlight.options.include_gutter,
18401                                    border: None,
18402                                    background: highlight.color.into(),
18403                                    type_id: Some(highlight.type_id),
18404                                },
18405                            );
18406                        }
18407                    }
18408                    unique_rows
18409                },
18410            )
18411    }
18412
18413    pub fn highlighted_display_row_for_autoscroll(
18414        &self,
18415        snapshot: &DisplaySnapshot,
18416    ) -> Option<DisplayRow> {
18417        self.highlighted_rows
18418            .values()
18419            .flat_map(|highlighted_rows| highlighted_rows.iter())
18420            .filter_map(|highlight| {
18421                if highlight.options.autoscroll {
18422                    Some(highlight.range.start.to_display_point(snapshot).row())
18423                } else {
18424                    None
18425                }
18426            })
18427            .min()
18428    }
18429
18430    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18431        self.highlight_background::<SearchWithinRange>(
18432            ranges,
18433            |colors| colors.editor_document_highlight_read_background,
18434            cx,
18435        )
18436    }
18437
18438    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18439        self.breadcrumb_header = Some(new_header);
18440    }
18441
18442    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18443        self.clear_background_highlights::<SearchWithinRange>(cx);
18444    }
18445
18446    pub fn highlight_background<T: 'static>(
18447        &mut self,
18448        ranges: &[Range<Anchor>],
18449        color_fetcher: fn(&ThemeColors) -> Hsla,
18450        cx: &mut Context<Self>,
18451    ) {
18452        self.background_highlights
18453            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18454        self.scrollbar_marker_state.dirty = true;
18455        cx.notify();
18456    }
18457
18458    pub fn clear_background_highlights<T: 'static>(
18459        &mut self,
18460        cx: &mut Context<Self>,
18461    ) -> Option<BackgroundHighlight> {
18462        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18463        if !text_highlights.1.is_empty() {
18464            self.scrollbar_marker_state.dirty = true;
18465            cx.notify();
18466        }
18467        Some(text_highlights)
18468    }
18469
18470    pub fn highlight_gutter<T: 'static>(
18471        &mut self,
18472        ranges: impl Into<Vec<Range<Anchor>>>,
18473        color_fetcher: fn(&App) -> Hsla,
18474        cx: &mut Context<Self>,
18475    ) {
18476        self.gutter_highlights
18477            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18478        cx.notify();
18479    }
18480
18481    pub fn clear_gutter_highlights<T: 'static>(
18482        &mut self,
18483        cx: &mut Context<Self>,
18484    ) -> Option<GutterHighlight> {
18485        cx.notify();
18486        self.gutter_highlights.remove(&TypeId::of::<T>())
18487    }
18488
18489    pub fn insert_gutter_highlight<T: 'static>(
18490        &mut self,
18491        range: Range<Anchor>,
18492        color_fetcher: fn(&App) -> Hsla,
18493        cx: &mut Context<Self>,
18494    ) {
18495        let snapshot = self.buffer().read(cx).snapshot(cx);
18496        let mut highlights = self
18497            .gutter_highlights
18498            .remove(&TypeId::of::<T>())
18499            .map(|(_, highlights)| highlights)
18500            .unwrap_or_default();
18501        let ix = highlights.binary_search_by(|highlight| {
18502            Ordering::Equal
18503                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18504                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18505        });
18506        if let Err(ix) = ix {
18507            highlights.insert(ix, range);
18508        }
18509        self.gutter_highlights
18510            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18511    }
18512
18513    pub fn remove_gutter_highlights<T: 'static>(
18514        &mut self,
18515        ranges_to_remove: Vec<Range<Anchor>>,
18516        cx: &mut Context<Self>,
18517    ) {
18518        let snapshot = self.buffer().read(cx).snapshot(cx);
18519        let Some((color_fetcher, mut gutter_highlights)) =
18520            self.gutter_highlights.remove(&TypeId::of::<T>())
18521        else {
18522            return;
18523        };
18524        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18525        gutter_highlights.retain(|highlight| {
18526            while let Some(range_to_remove) = ranges_to_remove.peek() {
18527                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18528                    Ordering::Less | Ordering::Equal => {
18529                        ranges_to_remove.next();
18530                    }
18531                    Ordering::Greater => {
18532                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18533                            Ordering::Less | Ordering::Equal => {
18534                                return false;
18535                            }
18536                            Ordering::Greater => break,
18537                        }
18538                    }
18539                }
18540            }
18541
18542            true
18543        });
18544        self.gutter_highlights
18545            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18546    }
18547
18548    #[cfg(feature = "test-support")]
18549    pub fn all_text_background_highlights(
18550        &self,
18551        window: &mut Window,
18552        cx: &mut Context<Self>,
18553    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18554        let snapshot = self.snapshot(window, cx);
18555        let buffer = &snapshot.buffer_snapshot;
18556        let start = buffer.anchor_before(0);
18557        let end = buffer.anchor_after(buffer.len());
18558        let theme = cx.theme().colors();
18559        self.background_highlights_in_range(start..end, &snapshot, theme)
18560    }
18561
18562    #[cfg(feature = "test-support")]
18563    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18564        let snapshot = self.buffer().read(cx).snapshot(cx);
18565
18566        let highlights = self
18567            .background_highlights
18568            .get(&TypeId::of::<items::BufferSearchHighlights>());
18569
18570        if let Some((_color, ranges)) = highlights {
18571            ranges
18572                .iter()
18573                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18574                .collect_vec()
18575        } else {
18576            vec![]
18577        }
18578    }
18579
18580    fn document_highlights_for_position<'a>(
18581        &'a self,
18582        position: Anchor,
18583        buffer: &'a MultiBufferSnapshot,
18584    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18585        let read_highlights = self
18586            .background_highlights
18587            .get(&TypeId::of::<DocumentHighlightRead>())
18588            .map(|h| &h.1);
18589        let write_highlights = self
18590            .background_highlights
18591            .get(&TypeId::of::<DocumentHighlightWrite>())
18592            .map(|h| &h.1);
18593        let left_position = position.bias_left(buffer);
18594        let right_position = position.bias_right(buffer);
18595        read_highlights
18596            .into_iter()
18597            .chain(write_highlights)
18598            .flat_map(move |ranges| {
18599                let start_ix = match ranges.binary_search_by(|probe| {
18600                    let cmp = probe.end.cmp(&left_position, buffer);
18601                    if cmp.is_ge() {
18602                        Ordering::Greater
18603                    } else {
18604                        Ordering::Less
18605                    }
18606                }) {
18607                    Ok(i) | Err(i) => i,
18608                };
18609
18610                ranges[start_ix..]
18611                    .iter()
18612                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18613            })
18614    }
18615
18616    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18617        self.background_highlights
18618            .get(&TypeId::of::<T>())
18619            .map_or(false, |(_, highlights)| !highlights.is_empty())
18620    }
18621
18622    pub fn background_highlights_in_range(
18623        &self,
18624        search_range: Range<Anchor>,
18625        display_snapshot: &DisplaySnapshot,
18626        theme: &ThemeColors,
18627    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18628        let mut results = Vec::new();
18629        for (color_fetcher, ranges) in self.background_highlights.values() {
18630            let color = color_fetcher(theme);
18631            let start_ix = match ranges.binary_search_by(|probe| {
18632                let cmp = probe
18633                    .end
18634                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18635                if cmp.is_gt() {
18636                    Ordering::Greater
18637                } else {
18638                    Ordering::Less
18639                }
18640            }) {
18641                Ok(i) | Err(i) => i,
18642            };
18643            for range in &ranges[start_ix..] {
18644                if range
18645                    .start
18646                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18647                    .is_ge()
18648                {
18649                    break;
18650                }
18651
18652                let start = range.start.to_display_point(display_snapshot);
18653                let end = range.end.to_display_point(display_snapshot);
18654                results.push((start..end, color))
18655            }
18656        }
18657        results
18658    }
18659
18660    pub fn background_highlight_row_ranges<T: 'static>(
18661        &self,
18662        search_range: Range<Anchor>,
18663        display_snapshot: &DisplaySnapshot,
18664        count: usize,
18665    ) -> Vec<RangeInclusive<DisplayPoint>> {
18666        let mut results = Vec::new();
18667        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18668            return vec![];
18669        };
18670
18671        let start_ix = match ranges.binary_search_by(|probe| {
18672            let cmp = probe
18673                .end
18674                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18675            if cmp.is_gt() {
18676                Ordering::Greater
18677            } else {
18678                Ordering::Less
18679            }
18680        }) {
18681            Ok(i) | Err(i) => i,
18682        };
18683        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18684            if let (Some(start_display), Some(end_display)) = (start, end) {
18685                results.push(
18686                    start_display.to_display_point(display_snapshot)
18687                        ..=end_display.to_display_point(display_snapshot),
18688                );
18689            }
18690        };
18691        let mut start_row: Option<Point> = None;
18692        let mut end_row: Option<Point> = None;
18693        if ranges.len() > count {
18694            return Vec::new();
18695        }
18696        for range in &ranges[start_ix..] {
18697            if range
18698                .start
18699                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18700                .is_ge()
18701            {
18702                break;
18703            }
18704            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18705            if let Some(current_row) = &end_row {
18706                if end.row == current_row.row {
18707                    continue;
18708                }
18709            }
18710            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18711            if start_row.is_none() {
18712                assert_eq!(end_row, None);
18713                start_row = Some(start);
18714                end_row = Some(end);
18715                continue;
18716            }
18717            if let Some(current_end) = end_row.as_mut() {
18718                if start.row > current_end.row + 1 {
18719                    push_region(start_row, end_row);
18720                    start_row = Some(start);
18721                    end_row = Some(end);
18722                } else {
18723                    // Merge two hunks.
18724                    *current_end = end;
18725                }
18726            } else {
18727                unreachable!();
18728            }
18729        }
18730        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18731        push_region(start_row, end_row);
18732        results
18733    }
18734
18735    pub fn gutter_highlights_in_range(
18736        &self,
18737        search_range: Range<Anchor>,
18738        display_snapshot: &DisplaySnapshot,
18739        cx: &App,
18740    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18741        let mut results = Vec::new();
18742        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18743            let color = color_fetcher(cx);
18744            let start_ix = match ranges.binary_search_by(|probe| {
18745                let cmp = probe
18746                    .end
18747                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18748                if cmp.is_gt() {
18749                    Ordering::Greater
18750                } else {
18751                    Ordering::Less
18752                }
18753            }) {
18754                Ok(i) | Err(i) => i,
18755            };
18756            for range in &ranges[start_ix..] {
18757                if range
18758                    .start
18759                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18760                    .is_ge()
18761                {
18762                    break;
18763                }
18764
18765                let start = range.start.to_display_point(display_snapshot);
18766                let end = range.end.to_display_point(display_snapshot);
18767                results.push((start..end, color))
18768            }
18769        }
18770        results
18771    }
18772
18773    /// Get the text ranges corresponding to the redaction query
18774    pub fn redacted_ranges(
18775        &self,
18776        search_range: Range<Anchor>,
18777        display_snapshot: &DisplaySnapshot,
18778        cx: &App,
18779    ) -> Vec<Range<DisplayPoint>> {
18780        display_snapshot
18781            .buffer_snapshot
18782            .redacted_ranges(search_range, |file| {
18783                if let Some(file) = file {
18784                    file.is_private()
18785                        && EditorSettings::get(
18786                            Some(SettingsLocation {
18787                                worktree_id: file.worktree_id(cx),
18788                                path: file.path().as_ref(),
18789                            }),
18790                            cx,
18791                        )
18792                        .redact_private_values
18793                } else {
18794                    false
18795                }
18796            })
18797            .map(|range| {
18798                range.start.to_display_point(display_snapshot)
18799                    ..range.end.to_display_point(display_snapshot)
18800            })
18801            .collect()
18802    }
18803
18804    pub fn highlight_text<T: 'static>(
18805        &mut self,
18806        ranges: Vec<Range<Anchor>>,
18807        style: HighlightStyle,
18808        cx: &mut Context<Self>,
18809    ) {
18810        self.display_map.update(cx, |map, _| {
18811            map.highlight_text(TypeId::of::<T>(), ranges, style)
18812        });
18813        cx.notify();
18814    }
18815
18816    pub(crate) fn highlight_inlays<T: 'static>(
18817        &mut self,
18818        highlights: Vec<InlayHighlight>,
18819        style: HighlightStyle,
18820        cx: &mut Context<Self>,
18821    ) {
18822        self.display_map.update(cx, |map, _| {
18823            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18824        });
18825        cx.notify();
18826    }
18827
18828    pub fn text_highlights<'a, T: 'static>(
18829        &'a self,
18830        cx: &'a App,
18831    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18832        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18833    }
18834
18835    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18836        let cleared = self
18837            .display_map
18838            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18839        if cleared {
18840            cx.notify();
18841        }
18842    }
18843
18844    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18845        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18846            && self.focus_handle.is_focused(window)
18847    }
18848
18849    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18850        self.show_cursor_when_unfocused = is_enabled;
18851        cx.notify();
18852    }
18853
18854    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18855        cx.notify();
18856    }
18857
18858    fn on_debug_session_event(
18859        &mut self,
18860        _session: Entity<Session>,
18861        event: &SessionEvent,
18862        cx: &mut Context<Self>,
18863    ) {
18864        match event {
18865            SessionEvent::InvalidateInlineValue => {
18866                self.refresh_inline_values(cx);
18867            }
18868            _ => {}
18869        }
18870    }
18871
18872    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18873        let Some(project) = self.project.clone() else {
18874            return;
18875        };
18876
18877        if !self.inline_value_cache.enabled {
18878            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18879            self.splice_inlays(&inlays, Vec::new(), cx);
18880            return;
18881        }
18882
18883        let current_execution_position = self
18884            .highlighted_rows
18885            .get(&TypeId::of::<ActiveDebugLine>())
18886            .and_then(|lines| lines.last().map(|line| line.range.start));
18887
18888        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18889            let inline_values = editor
18890                .update(cx, |editor, cx| {
18891                    let Some(current_execution_position) = current_execution_position else {
18892                        return Some(Task::ready(Ok(Vec::new())));
18893                    };
18894
18895                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18896                        let snapshot = buffer.snapshot(cx);
18897
18898                        let excerpt = snapshot.excerpt_containing(
18899                            current_execution_position..current_execution_position,
18900                        )?;
18901
18902                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18903                    })?;
18904
18905                    let range =
18906                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18907
18908                    project.inline_values(buffer, range, cx)
18909                })
18910                .ok()
18911                .flatten()?
18912                .await
18913                .context("refreshing debugger inlays")
18914                .log_err()?;
18915
18916            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18917
18918            for (buffer_id, inline_value) in inline_values
18919                .into_iter()
18920                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18921            {
18922                buffer_inline_values
18923                    .entry(buffer_id)
18924                    .or_default()
18925                    .push(inline_value);
18926            }
18927
18928            editor
18929                .update(cx, |editor, cx| {
18930                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18931                    let mut new_inlays = Vec::default();
18932
18933                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18934                        let buffer_id = buffer_snapshot.remote_id();
18935                        buffer_inline_values
18936                            .get(&buffer_id)
18937                            .into_iter()
18938                            .flatten()
18939                            .for_each(|hint| {
18940                                let inlay = Inlay::debugger_hint(
18941                                    post_inc(&mut editor.next_inlay_id),
18942                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18943                                    hint.text(),
18944                                );
18945
18946                                new_inlays.push(inlay);
18947                            });
18948                    }
18949
18950                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18951                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18952
18953                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18954                })
18955                .ok()?;
18956            Some(())
18957        });
18958    }
18959
18960    fn on_buffer_event(
18961        &mut self,
18962        multibuffer: &Entity<MultiBuffer>,
18963        event: &multi_buffer::Event,
18964        window: &mut Window,
18965        cx: &mut Context<Self>,
18966    ) {
18967        match event {
18968            multi_buffer::Event::Edited {
18969                singleton_buffer_edited,
18970                edited_buffer,
18971            } => {
18972                self.scrollbar_marker_state.dirty = true;
18973                self.active_indent_guides_state.dirty = true;
18974                self.refresh_active_diagnostics(cx);
18975                self.refresh_code_actions(window, cx);
18976                self.refresh_selected_text_highlights(true, window, cx);
18977                refresh_matching_bracket_highlights(self, window, cx);
18978                if self.has_active_inline_completion() {
18979                    self.update_visible_inline_completion(window, cx);
18980                }
18981                if let Some(project) = self.project.as_ref() {
18982                    if let Some(edited_buffer) = edited_buffer {
18983                        project.update(cx, |project, cx| {
18984                            self.registered_buffers
18985                                .entry(edited_buffer.read(cx).remote_id())
18986                                .or_insert_with(|| {
18987                                    project
18988                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18989                                });
18990                        });
18991                        if edited_buffer.read(cx).file().is_some() {
18992                            self.pull_diagnostics(
18993                                Some(edited_buffer.read(cx).remote_id()),
18994                                window,
18995                                cx,
18996                            );
18997                        }
18998                    }
18999                }
19000                cx.emit(EditorEvent::BufferEdited);
19001                cx.emit(SearchEvent::MatchesInvalidated);
19002                if *singleton_buffer_edited {
19003                    if let Some(buffer) = edited_buffer {
19004                        if buffer.read(cx).file().is_none() {
19005                            cx.emit(EditorEvent::TitleChanged);
19006                        }
19007                    }
19008                    if let Some(project) = &self.project {
19009                        #[allow(clippy::mutable_key_type)]
19010                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19011                            multibuffer
19012                                .all_buffers()
19013                                .into_iter()
19014                                .filter_map(|buffer| {
19015                                    buffer.update(cx, |buffer, cx| {
19016                                        let language = buffer.language()?;
19017                                        let should_discard = project.update(cx, |project, cx| {
19018                                            project.is_local()
19019                                                && !project.has_language_servers_for(buffer, cx)
19020                                        });
19021                                        should_discard.not().then_some(language.clone())
19022                                    })
19023                                })
19024                                .collect::<HashSet<_>>()
19025                        });
19026                        if !languages_affected.is_empty() {
19027                            self.refresh_inlay_hints(
19028                                InlayHintRefreshReason::BufferEdited(languages_affected),
19029                                cx,
19030                            );
19031                        }
19032                    }
19033                }
19034
19035                let Some(project) = &self.project else { return };
19036                let (telemetry, is_via_ssh) = {
19037                    let project = project.read(cx);
19038                    let telemetry = project.client().telemetry().clone();
19039                    let is_via_ssh = project.is_via_ssh();
19040                    (telemetry, is_via_ssh)
19041                };
19042                refresh_linked_ranges(self, window, cx);
19043                telemetry.log_edit_event("editor", is_via_ssh);
19044            }
19045            multi_buffer::Event::ExcerptsAdded {
19046                buffer,
19047                predecessor,
19048                excerpts,
19049            } => {
19050                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19051                let buffer_id = buffer.read(cx).remote_id();
19052                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19053                    if let Some(project) = &self.project {
19054                        update_uncommitted_diff_for_buffer(
19055                            cx.entity(),
19056                            project,
19057                            [buffer.clone()],
19058                            self.buffer.clone(),
19059                            cx,
19060                        )
19061                        .detach();
19062                    }
19063                }
19064                cx.emit(EditorEvent::ExcerptsAdded {
19065                    buffer: buffer.clone(),
19066                    predecessor: *predecessor,
19067                    excerpts: excerpts.clone(),
19068                });
19069                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19070            }
19071            multi_buffer::Event::ExcerptsRemoved {
19072                ids,
19073                removed_buffer_ids,
19074            } => {
19075                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19076                let buffer = self.buffer.read(cx);
19077                self.registered_buffers
19078                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19079                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19080                cx.emit(EditorEvent::ExcerptsRemoved {
19081                    ids: ids.clone(),
19082                    removed_buffer_ids: removed_buffer_ids.clone(),
19083                })
19084            }
19085            multi_buffer::Event::ExcerptsEdited {
19086                excerpt_ids,
19087                buffer_ids,
19088            } => {
19089                self.display_map.update(cx, |map, cx| {
19090                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19091                });
19092                cx.emit(EditorEvent::ExcerptsEdited {
19093                    ids: excerpt_ids.clone(),
19094                })
19095            }
19096            multi_buffer::Event::ExcerptsExpanded { ids } => {
19097                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19098                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19099            }
19100            multi_buffer::Event::Reparsed(buffer_id) => {
19101                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19102                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19103
19104                cx.emit(EditorEvent::Reparsed(*buffer_id));
19105            }
19106            multi_buffer::Event::DiffHunksToggled => {
19107                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19108            }
19109            multi_buffer::Event::LanguageChanged(buffer_id) => {
19110                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19111                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19112                cx.emit(EditorEvent::Reparsed(*buffer_id));
19113                cx.notify();
19114            }
19115            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19116            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19117            multi_buffer::Event::FileHandleChanged
19118            | multi_buffer::Event::Reloaded
19119            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19120            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19121            multi_buffer::Event::DiagnosticsUpdated => {
19122                self.update_diagnostics_state(window, cx);
19123            }
19124            _ => {}
19125        };
19126    }
19127
19128    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19129        self.refresh_active_diagnostics(cx);
19130        self.refresh_inline_diagnostics(true, window, cx);
19131        self.scrollbar_marker_state.dirty = true;
19132        cx.notify();
19133    }
19134
19135    pub fn start_temporary_diff_override(&mut self) {
19136        self.load_diff_task.take();
19137        self.temporary_diff_override = true;
19138    }
19139
19140    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19141        self.temporary_diff_override = false;
19142        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19143        self.buffer.update(cx, |buffer, cx| {
19144            buffer.set_all_diff_hunks_collapsed(cx);
19145        });
19146
19147        if let Some(project) = self.project.clone() {
19148            self.load_diff_task = Some(
19149                update_uncommitted_diff_for_buffer(
19150                    cx.entity(),
19151                    &project,
19152                    self.buffer.read(cx).all_buffers(),
19153                    self.buffer.clone(),
19154                    cx,
19155                )
19156                .shared(),
19157            );
19158        }
19159    }
19160
19161    fn on_display_map_changed(
19162        &mut self,
19163        _: Entity<DisplayMap>,
19164        _: &mut Window,
19165        cx: &mut Context<Self>,
19166    ) {
19167        cx.notify();
19168    }
19169
19170    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19171        let new_severity = if self.diagnostics_enabled() {
19172            EditorSettings::get_global(cx)
19173                .diagnostics_max_severity
19174                .unwrap_or(DiagnosticSeverity::Hint)
19175        } else {
19176            DiagnosticSeverity::Off
19177        };
19178        self.set_max_diagnostics_severity(new_severity, cx);
19179        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19180        self.update_edit_prediction_settings(cx);
19181        self.refresh_inline_completion(true, false, window, cx);
19182        self.refresh_inlay_hints(
19183            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19184                self.selections.newest_anchor().head(),
19185                &self.buffer.read(cx).snapshot(cx),
19186                cx,
19187            )),
19188            cx,
19189        );
19190
19191        let old_cursor_shape = self.cursor_shape;
19192
19193        {
19194            let editor_settings = EditorSettings::get_global(cx);
19195            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19196            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19197            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19198            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19199            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19200        }
19201
19202        if old_cursor_shape != self.cursor_shape {
19203            cx.emit(EditorEvent::CursorShapeChanged);
19204        }
19205
19206        let project_settings = ProjectSettings::get_global(cx);
19207        self.serialize_dirty_buffers =
19208            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19209
19210        if self.mode.is_full() {
19211            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19212            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19213            if self.show_inline_diagnostics != show_inline_diagnostics {
19214                self.show_inline_diagnostics = show_inline_diagnostics;
19215                self.refresh_inline_diagnostics(false, window, cx);
19216            }
19217
19218            if self.git_blame_inline_enabled != inline_blame_enabled {
19219                self.toggle_git_blame_inline_internal(false, window, cx);
19220            }
19221
19222            let minimap_settings = EditorSettings::get_global(cx).minimap;
19223            if self.minimap_visibility != MinimapVisibility::Disabled {
19224                if self.minimap_visibility.settings_visibility()
19225                    != minimap_settings.minimap_enabled()
19226                {
19227                    self.set_minimap_visibility(
19228                        MinimapVisibility::for_mode(self.mode(), cx),
19229                        window,
19230                        cx,
19231                    );
19232                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19233                    minimap_entity.update(cx, |minimap_editor, cx| {
19234                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19235                    })
19236                }
19237            }
19238        }
19239
19240        cx.notify();
19241    }
19242
19243    pub fn set_searchable(&mut self, searchable: bool) {
19244        self.searchable = searchable;
19245    }
19246
19247    pub fn searchable(&self) -> bool {
19248        self.searchable
19249    }
19250
19251    fn open_proposed_changes_editor(
19252        &mut self,
19253        _: &OpenProposedChangesEditor,
19254        window: &mut Window,
19255        cx: &mut Context<Self>,
19256    ) {
19257        let Some(workspace) = self.workspace() else {
19258            cx.propagate();
19259            return;
19260        };
19261
19262        let selections = self.selections.all::<usize>(cx);
19263        let multi_buffer = self.buffer.read(cx);
19264        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19265        let mut new_selections_by_buffer = HashMap::default();
19266        for selection in selections {
19267            for (buffer, range, _) in
19268                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19269            {
19270                let mut range = range.to_point(buffer);
19271                range.start.column = 0;
19272                range.end.column = buffer.line_len(range.end.row);
19273                new_selections_by_buffer
19274                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19275                    .or_insert(Vec::new())
19276                    .push(range)
19277            }
19278        }
19279
19280        let proposed_changes_buffers = new_selections_by_buffer
19281            .into_iter()
19282            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19283            .collect::<Vec<_>>();
19284        let proposed_changes_editor = cx.new(|cx| {
19285            ProposedChangesEditor::new(
19286                "Proposed changes",
19287                proposed_changes_buffers,
19288                self.project.clone(),
19289                window,
19290                cx,
19291            )
19292        });
19293
19294        window.defer(cx, move |window, cx| {
19295            workspace.update(cx, |workspace, cx| {
19296                workspace.active_pane().update(cx, |pane, cx| {
19297                    pane.add_item(
19298                        Box::new(proposed_changes_editor),
19299                        true,
19300                        true,
19301                        None,
19302                        window,
19303                        cx,
19304                    );
19305                });
19306            });
19307        });
19308    }
19309
19310    pub fn open_excerpts_in_split(
19311        &mut self,
19312        _: &OpenExcerptsSplit,
19313        window: &mut Window,
19314        cx: &mut Context<Self>,
19315    ) {
19316        self.open_excerpts_common(None, true, window, cx)
19317    }
19318
19319    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19320        self.open_excerpts_common(None, false, window, cx)
19321    }
19322
19323    fn open_excerpts_common(
19324        &mut self,
19325        jump_data: Option<JumpData>,
19326        split: bool,
19327        window: &mut Window,
19328        cx: &mut Context<Self>,
19329    ) {
19330        let Some(workspace) = self.workspace() else {
19331            cx.propagate();
19332            return;
19333        };
19334
19335        if self.buffer.read(cx).is_singleton() {
19336            cx.propagate();
19337            return;
19338        }
19339
19340        let mut new_selections_by_buffer = HashMap::default();
19341        match &jump_data {
19342            Some(JumpData::MultiBufferPoint {
19343                excerpt_id,
19344                position,
19345                anchor,
19346                line_offset_from_top,
19347            }) => {
19348                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19349                if let Some(buffer) = multi_buffer_snapshot
19350                    .buffer_id_for_excerpt(*excerpt_id)
19351                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19352                {
19353                    let buffer_snapshot = buffer.read(cx).snapshot();
19354                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19355                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19356                    } else {
19357                        buffer_snapshot.clip_point(*position, Bias::Left)
19358                    };
19359                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19360                    new_selections_by_buffer.insert(
19361                        buffer,
19362                        (
19363                            vec![jump_to_offset..jump_to_offset],
19364                            Some(*line_offset_from_top),
19365                        ),
19366                    );
19367                }
19368            }
19369            Some(JumpData::MultiBufferRow {
19370                row,
19371                line_offset_from_top,
19372            }) => {
19373                let point = MultiBufferPoint::new(row.0, 0);
19374                if let Some((buffer, buffer_point, _)) =
19375                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19376                {
19377                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19378                    new_selections_by_buffer
19379                        .entry(buffer)
19380                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19381                        .0
19382                        .push(buffer_offset..buffer_offset)
19383                }
19384            }
19385            None => {
19386                let selections = self.selections.all::<usize>(cx);
19387                let multi_buffer = self.buffer.read(cx);
19388                for selection in selections {
19389                    for (snapshot, range, _, anchor) in multi_buffer
19390                        .snapshot(cx)
19391                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19392                    {
19393                        if let Some(anchor) = anchor {
19394                            // selection is in a deleted hunk
19395                            let Some(buffer_id) = anchor.buffer_id else {
19396                                continue;
19397                            };
19398                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19399                                continue;
19400                            };
19401                            let offset = text::ToOffset::to_offset(
19402                                &anchor.text_anchor,
19403                                &buffer_handle.read(cx).snapshot(),
19404                            );
19405                            let range = offset..offset;
19406                            new_selections_by_buffer
19407                                .entry(buffer_handle)
19408                                .or_insert((Vec::new(), None))
19409                                .0
19410                                .push(range)
19411                        } else {
19412                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19413                            else {
19414                                continue;
19415                            };
19416                            new_selections_by_buffer
19417                                .entry(buffer_handle)
19418                                .or_insert((Vec::new(), None))
19419                                .0
19420                                .push(range)
19421                        }
19422                    }
19423                }
19424            }
19425        }
19426
19427        new_selections_by_buffer
19428            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19429
19430        if new_selections_by_buffer.is_empty() {
19431            return;
19432        }
19433
19434        // We defer the pane interaction because we ourselves are a workspace item
19435        // and activating a new item causes the pane to call a method on us reentrantly,
19436        // which panics if we're on the stack.
19437        window.defer(cx, move |window, cx| {
19438            workspace.update(cx, |workspace, cx| {
19439                let pane = if split {
19440                    workspace.adjacent_pane(window, cx)
19441                } else {
19442                    workspace.active_pane().clone()
19443                };
19444
19445                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19446                    let editor = buffer
19447                        .read(cx)
19448                        .file()
19449                        .is_none()
19450                        .then(|| {
19451                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19452                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19453                            // Instead, we try to activate the existing editor in the pane first.
19454                            let (editor, pane_item_index) =
19455                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19456                                    let editor = item.downcast::<Editor>()?;
19457                                    let singleton_buffer =
19458                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19459                                    if singleton_buffer == buffer {
19460                                        Some((editor, i))
19461                                    } else {
19462                                        None
19463                                    }
19464                                })?;
19465                            pane.update(cx, |pane, cx| {
19466                                pane.activate_item(pane_item_index, true, true, window, cx)
19467                            });
19468                            Some(editor)
19469                        })
19470                        .flatten()
19471                        .unwrap_or_else(|| {
19472                            workspace.open_project_item::<Self>(
19473                                pane.clone(),
19474                                buffer,
19475                                true,
19476                                true,
19477                                window,
19478                                cx,
19479                            )
19480                        });
19481
19482                    editor.update(cx, |editor, cx| {
19483                        let autoscroll = match scroll_offset {
19484                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19485                            None => Autoscroll::newest(),
19486                        };
19487                        let nav_history = editor.nav_history.take();
19488                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19489                            s.select_ranges(ranges);
19490                        });
19491                        editor.nav_history = nav_history;
19492                    });
19493                }
19494            })
19495        });
19496    }
19497
19498    // For now, don't allow opening excerpts in buffers that aren't backed by
19499    // regular project files.
19500    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19501        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19502    }
19503
19504    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19505        let snapshot = self.buffer.read(cx).read(cx);
19506        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19507        Some(
19508            ranges
19509                .iter()
19510                .map(move |range| {
19511                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19512                })
19513                .collect(),
19514        )
19515    }
19516
19517    fn selection_replacement_ranges(
19518        &self,
19519        range: Range<OffsetUtf16>,
19520        cx: &mut App,
19521    ) -> Vec<Range<OffsetUtf16>> {
19522        let selections = self.selections.all::<OffsetUtf16>(cx);
19523        let newest_selection = selections
19524            .iter()
19525            .max_by_key(|selection| selection.id)
19526            .unwrap();
19527        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19528        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19529        let snapshot = self.buffer.read(cx).read(cx);
19530        selections
19531            .into_iter()
19532            .map(|mut selection| {
19533                selection.start.0 =
19534                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19535                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19536                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19537                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19538            })
19539            .collect()
19540    }
19541
19542    fn report_editor_event(
19543        &self,
19544        event_type: &'static str,
19545        file_extension: Option<String>,
19546        cx: &App,
19547    ) {
19548        if cfg!(any(test, feature = "test-support")) {
19549            return;
19550        }
19551
19552        let Some(project) = &self.project else { return };
19553
19554        // If None, we are in a file without an extension
19555        let file = self
19556            .buffer
19557            .read(cx)
19558            .as_singleton()
19559            .and_then(|b| b.read(cx).file());
19560        let file_extension = file_extension.or(file
19561            .as_ref()
19562            .and_then(|file| Path::new(file.file_name(cx)).extension())
19563            .and_then(|e| e.to_str())
19564            .map(|a| a.to_string()));
19565
19566        let vim_mode = vim_enabled(cx);
19567
19568        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19569        let copilot_enabled = edit_predictions_provider
19570            == language::language_settings::EditPredictionProvider::Copilot;
19571        let copilot_enabled_for_language = self
19572            .buffer
19573            .read(cx)
19574            .language_settings(cx)
19575            .show_edit_predictions;
19576
19577        let project = project.read(cx);
19578        telemetry::event!(
19579            event_type,
19580            file_extension,
19581            vim_mode,
19582            copilot_enabled,
19583            copilot_enabled_for_language,
19584            edit_predictions_provider,
19585            is_via_ssh = project.is_via_ssh(),
19586        );
19587    }
19588
19589    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19590    /// with each line being an array of {text, highlight} objects.
19591    fn copy_highlight_json(
19592        &mut self,
19593        _: &CopyHighlightJson,
19594        window: &mut Window,
19595        cx: &mut Context<Self>,
19596    ) {
19597        #[derive(Serialize)]
19598        struct Chunk<'a> {
19599            text: String,
19600            highlight: Option<&'a str>,
19601        }
19602
19603        let snapshot = self.buffer.read(cx).snapshot(cx);
19604        let range = self
19605            .selected_text_range(false, window, cx)
19606            .and_then(|selection| {
19607                if selection.range.is_empty() {
19608                    None
19609                } else {
19610                    Some(selection.range)
19611                }
19612            })
19613            .unwrap_or_else(|| 0..snapshot.len());
19614
19615        let chunks = snapshot.chunks(range, true);
19616        let mut lines = Vec::new();
19617        let mut line: VecDeque<Chunk> = VecDeque::new();
19618
19619        let Some(style) = self.style.as_ref() else {
19620            return;
19621        };
19622
19623        for chunk in chunks {
19624            let highlight = chunk
19625                .syntax_highlight_id
19626                .and_then(|id| id.name(&style.syntax));
19627            let mut chunk_lines = chunk.text.split('\n').peekable();
19628            while let Some(text) = chunk_lines.next() {
19629                let mut merged_with_last_token = false;
19630                if let Some(last_token) = line.back_mut() {
19631                    if last_token.highlight == highlight {
19632                        last_token.text.push_str(text);
19633                        merged_with_last_token = true;
19634                    }
19635                }
19636
19637                if !merged_with_last_token {
19638                    line.push_back(Chunk {
19639                        text: text.into(),
19640                        highlight,
19641                    });
19642                }
19643
19644                if chunk_lines.peek().is_some() {
19645                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19646                        line.pop_front();
19647                    }
19648                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19649                        line.pop_back();
19650                    }
19651
19652                    lines.push(mem::take(&mut line));
19653                }
19654            }
19655        }
19656
19657        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19658            return;
19659        };
19660        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19661    }
19662
19663    pub fn open_context_menu(
19664        &mut self,
19665        _: &OpenContextMenu,
19666        window: &mut Window,
19667        cx: &mut Context<Self>,
19668    ) {
19669        self.request_autoscroll(Autoscroll::newest(), cx);
19670        let position = self.selections.newest_display(cx).start;
19671        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19672    }
19673
19674    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19675        &self.inlay_hint_cache
19676    }
19677
19678    pub fn replay_insert_event(
19679        &mut self,
19680        text: &str,
19681        relative_utf16_range: Option<Range<isize>>,
19682        window: &mut Window,
19683        cx: &mut Context<Self>,
19684    ) {
19685        if !self.input_enabled {
19686            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19687            return;
19688        }
19689        if let Some(relative_utf16_range) = relative_utf16_range {
19690            let selections = self.selections.all::<OffsetUtf16>(cx);
19691            self.change_selections(None, window, cx, |s| {
19692                let new_ranges = selections.into_iter().map(|range| {
19693                    let start = OffsetUtf16(
19694                        range
19695                            .head()
19696                            .0
19697                            .saturating_add_signed(relative_utf16_range.start),
19698                    );
19699                    let end = OffsetUtf16(
19700                        range
19701                            .head()
19702                            .0
19703                            .saturating_add_signed(relative_utf16_range.end),
19704                    );
19705                    start..end
19706                });
19707                s.select_ranges(new_ranges);
19708            });
19709        }
19710
19711        self.handle_input(text, window, cx);
19712    }
19713
19714    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19715        let Some(provider) = self.semantics_provider.as_ref() else {
19716            return false;
19717        };
19718
19719        let mut supports = false;
19720        self.buffer().update(cx, |this, cx| {
19721            this.for_each_buffer(|buffer| {
19722                supports |= provider.supports_inlay_hints(buffer, cx);
19723            });
19724        });
19725
19726        supports
19727    }
19728
19729    pub fn is_focused(&self, window: &Window) -> bool {
19730        self.focus_handle.is_focused(window)
19731    }
19732
19733    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19734        cx.emit(EditorEvent::Focused);
19735
19736        if let Some(descendant) = self
19737            .last_focused_descendant
19738            .take()
19739            .and_then(|descendant| descendant.upgrade())
19740        {
19741            window.focus(&descendant);
19742        } else {
19743            if let Some(blame) = self.blame.as_ref() {
19744                blame.update(cx, GitBlame::focus)
19745            }
19746
19747            self.blink_manager.update(cx, BlinkManager::enable);
19748            self.show_cursor_names(window, cx);
19749            self.buffer.update(cx, |buffer, cx| {
19750                buffer.finalize_last_transaction(cx);
19751                if self.leader_id.is_none() {
19752                    buffer.set_active_selections(
19753                        &self.selections.disjoint_anchors(),
19754                        self.selections.line_mode,
19755                        self.cursor_shape,
19756                        cx,
19757                    );
19758                }
19759            });
19760        }
19761    }
19762
19763    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19764        cx.emit(EditorEvent::FocusedIn)
19765    }
19766
19767    fn handle_focus_out(
19768        &mut self,
19769        event: FocusOutEvent,
19770        _window: &mut Window,
19771        cx: &mut Context<Self>,
19772    ) {
19773        if event.blurred != self.focus_handle {
19774            self.last_focused_descendant = Some(event.blurred);
19775        }
19776        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19777    }
19778
19779    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19780        self.blink_manager.update(cx, BlinkManager::disable);
19781        self.buffer
19782            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19783
19784        if let Some(blame) = self.blame.as_ref() {
19785            blame.update(cx, GitBlame::blur)
19786        }
19787        if !self.hover_state.focused(window, cx) {
19788            hide_hover(self, cx);
19789        }
19790        if !self
19791            .context_menu
19792            .borrow()
19793            .as_ref()
19794            .is_some_and(|context_menu| context_menu.focused(window, cx))
19795        {
19796            self.hide_context_menu(window, cx);
19797        }
19798        self.discard_inline_completion(false, cx);
19799        cx.emit(EditorEvent::Blurred);
19800        cx.notify();
19801    }
19802
19803    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19804        let mut pending: String = window
19805            .pending_input_keystrokes()
19806            .into_iter()
19807            .flatten()
19808            .filter_map(|keystroke| {
19809                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19810                    keystroke.key_char.clone()
19811                } else {
19812                    None
19813                }
19814            })
19815            .collect();
19816
19817        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19818            pending = "".to_string();
19819        }
19820
19821        let existing_pending = self
19822            .text_highlights::<PendingInput>(cx)
19823            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19824        if existing_pending.is_none() && pending.is_empty() {
19825            return;
19826        }
19827        let transaction =
19828            self.transact(window, cx, |this, window, cx| {
19829                let selections = this.selections.all::<usize>(cx);
19830                let edits = selections
19831                    .iter()
19832                    .map(|selection| (selection.end..selection.end, pending.clone()));
19833                this.edit(edits, cx);
19834                this.change_selections(None, window, cx, |s| {
19835                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19836                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19837                    }));
19838                });
19839                if let Some(existing_ranges) = existing_pending {
19840                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19841                    this.edit(edits, cx);
19842                }
19843            });
19844
19845        let snapshot = self.snapshot(window, cx);
19846        let ranges = self
19847            .selections
19848            .all::<usize>(cx)
19849            .into_iter()
19850            .map(|selection| {
19851                snapshot.buffer_snapshot.anchor_after(selection.end)
19852                    ..snapshot
19853                        .buffer_snapshot
19854                        .anchor_before(selection.end + pending.len())
19855            })
19856            .collect();
19857
19858        if pending.is_empty() {
19859            self.clear_highlights::<PendingInput>(cx);
19860        } else {
19861            self.highlight_text::<PendingInput>(
19862                ranges,
19863                HighlightStyle {
19864                    underline: Some(UnderlineStyle {
19865                        thickness: px(1.),
19866                        color: None,
19867                        wavy: false,
19868                    }),
19869                    ..Default::default()
19870                },
19871                cx,
19872            );
19873        }
19874
19875        self.ime_transaction = self.ime_transaction.or(transaction);
19876        if let Some(transaction) = self.ime_transaction {
19877            self.buffer.update(cx, |buffer, cx| {
19878                buffer.group_until_transaction(transaction, cx);
19879            });
19880        }
19881
19882        if self.text_highlights::<PendingInput>(cx).is_none() {
19883            self.ime_transaction.take();
19884        }
19885    }
19886
19887    pub fn register_action_renderer(
19888        &mut self,
19889        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19890    ) -> Subscription {
19891        let id = self.next_editor_action_id.post_inc();
19892        self.editor_actions
19893            .borrow_mut()
19894            .insert(id, Box::new(listener));
19895
19896        let editor_actions = self.editor_actions.clone();
19897        Subscription::new(move || {
19898            editor_actions.borrow_mut().remove(&id);
19899        })
19900    }
19901
19902    pub fn register_action<A: Action>(
19903        &mut self,
19904        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19905    ) -> Subscription {
19906        let id = self.next_editor_action_id.post_inc();
19907        let listener = Arc::new(listener);
19908        self.editor_actions.borrow_mut().insert(
19909            id,
19910            Box::new(move |_, window, _| {
19911                let listener = listener.clone();
19912                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19913                    let action = action.downcast_ref().unwrap();
19914                    if phase == DispatchPhase::Bubble {
19915                        listener(action, window, cx)
19916                    }
19917                })
19918            }),
19919        );
19920
19921        let editor_actions = self.editor_actions.clone();
19922        Subscription::new(move || {
19923            editor_actions.borrow_mut().remove(&id);
19924        })
19925    }
19926
19927    pub fn file_header_size(&self) -> u32 {
19928        FILE_HEADER_HEIGHT
19929    }
19930
19931    pub fn restore(
19932        &mut self,
19933        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19934        window: &mut Window,
19935        cx: &mut Context<Self>,
19936    ) {
19937        let workspace = self.workspace();
19938        let project = self.project.as_ref();
19939        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19940            let mut tasks = Vec::new();
19941            for (buffer_id, changes) in revert_changes {
19942                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19943                    buffer.update(cx, |buffer, cx| {
19944                        buffer.edit(
19945                            changes
19946                                .into_iter()
19947                                .map(|(range, text)| (range, text.to_string())),
19948                            None,
19949                            cx,
19950                        );
19951                    });
19952
19953                    if let Some(project) =
19954                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19955                    {
19956                        project.update(cx, |project, cx| {
19957                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19958                        })
19959                    }
19960                }
19961            }
19962            tasks
19963        });
19964        cx.spawn_in(window, async move |_, cx| {
19965            for (buffer, task) in save_tasks {
19966                let result = task.await;
19967                if result.is_err() {
19968                    let Some(path) = buffer
19969                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19970                        .ok()
19971                    else {
19972                        continue;
19973                    };
19974                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19975                        let Some(task) = cx
19976                            .update_window_entity(&workspace, |workspace, window, cx| {
19977                                workspace
19978                                    .open_path_preview(path, None, false, false, false, window, cx)
19979                            })
19980                            .ok()
19981                        else {
19982                            continue;
19983                        };
19984                        task.await.log_err();
19985                    }
19986                }
19987            }
19988        })
19989        .detach();
19990        self.change_selections(None, window, cx, |selections| selections.refresh());
19991    }
19992
19993    pub fn to_pixel_point(
19994        &self,
19995        source: multi_buffer::Anchor,
19996        editor_snapshot: &EditorSnapshot,
19997        window: &mut Window,
19998    ) -> Option<gpui::Point<Pixels>> {
19999        let source_point = source.to_display_point(editor_snapshot);
20000        self.display_to_pixel_point(source_point, editor_snapshot, window)
20001    }
20002
20003    pub fn display_to_pixel_point(
20004        &self,
20005        source: DisplayPoint,
20006        editor_snapshot: &EditorSnapshot,
20007        window: &mut Window,
20008    ) -> Option<gpui::Point<Pixels>> {
20009        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20010        let text_layout_details = self.text_layout_details(window);
20011        let scroll_top = text_layout_details
20012            .scroll_anchor
20013            .scroll_position(editor_snapshot)
20014            .y;
20015
20016        if source.row().as_f32() < scroll_top.floor() {
20017            return None;
20018        }
20019        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20020        let source_y = line_height * (source.row().as_f32() - scroll_top);
20021        Some(gpui::Point::new(source_x, source_y))
20022    }
20023
20024    pub fn has_visible_completions_menu(&self) -> bool {
20025        !self.edit_prediction_preview_is_active()
20026            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20027                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20028            })
20029    }
20030
20031    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20032        if self.mode.is_minimap() {
20033            return;
20034        }
20035        self.addons
20036            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20037    }
20038
20039    pub fn unregister_addon<T: Addon>(&mut self) {
20040        self.addons.remove(&std::any::TypeId::of::<T>());
20041    }
20042
20043    pub fn addon<T: Addon>(&self) -> Option<&T> {
20044        let type_id = std::any::TypeId::of::<T>();
20045        self.addons
20046            .get(&type_id)
20047            .and_then(|item| item.to_any().downcast_ref::<T>())
20048    }
20049
20050    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20051        let type_id = std::any::TypeId::of::<T>();
20052        self.addons
20053            .get_mut(&type_id)
20054            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20055    }
20056
20057    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20058        let text_layout_details = self.text_layout_details(window);
20059        let style = &text_layout_details.editor_style;
20060        let font_id = window.text_system().resolve_font(&style.text.font());
20061        let font_size = style.text.font_size.to_pixels(window.rem_size());
20062        let line_height = style.text.line_height_in_pixels(window.rem_size());
20063        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20064
20065        gpui::Size::new(em_width, line_height)
20066    }
20067
20068    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20069        self.load_diff_task.clone()
20070    }
20071
20072    fn read_metadata_from_db(
20073        &mut self,
20074        item_id: u64,
20075        workspace_id: WorkspaceId,
20076        window: &mut Window,
20077        cx: &mut Context<Editor>,
20078    ) {
20079        if self.is_singleton(cx)
20080            && !self.mode.is_minimap()
20081            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20082        {
20083            let buffer_snapshot = OnceCell::new();
20084
20085            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20086                if !folds.is_empty() {
20087                    let snapshot =
20088                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20089                    self.fold_ranges(
20090                        folds
20091                            .into_iter()
20092                            .map(|(start, end)| {
20093                                snapshot.clip_offset(start, Bias::Left)
20094                                    ..snapshot.clip_offset(end, Bias::Right)
20095                            })
20096                            .collect(),
20097                        false,
20098                        window,
20099                        cx,
20100                    );
20101                }
20102            }
20103
20104            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20105                if !selections.is_empty() {
20106                    let snapshot =
20107                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20108                    // skip adding the initial selection to selection history
20109                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20110                    self.change_selections(None, window, cx, |s| {
20111                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20112                            snapshot.clip_offset(start, Bias::Left)
20113                                ..snapshot.clip_offset(end, Bias::Right)
20114                        }));
20115                    });
20116                    self.selection_history.mode = SelectionHistoryMode::Normal;
20117                }
20118            };
20119        }
20120
20121        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20122    }
20123}
20124
20125fn vim_enabled(cx: &App) -> bool {
20126    cx.global::<SettingsStore>()
20127        .raw_user_settings()
20128        .get("vim_mode")
20129        == Some(&serde_json::Value::Bool(true))
20130}
20131
20132fn process_completion_for_edit(
20133    completion: &Completion,
20134    intent: CompletionIntent,
20135    buffer: &Entity<Buffer>,
20136    cursor_position: &text::Anchor,
20137    cx: &mut Context<Editor>,
20138) -> CompletionEdit {
20139    let buffer = buffer.read(cx);
20140    let buffer_snapshot = buffer.snapshot();
20141    let (snippet, new_text) = if completion.is_snippet() {
20142        // Workaround for typescript language server issues so that methods don't expand within
20143        // strings and functions with type expressions. The previous point is used because the query
20144        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20145        let mut snippet_source = completion.new_text.clone();
20146        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20147        previous_point.column = previous_point.column.saturating_sub(1);
20148        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20149            if scope.prefers_label_for_snippet_in_completion() {
20150                if let Some(label) = completion.label() {
20151                    if matches!(
20152                        completion.kind(),
20153                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20154                    ) {
20155                        snippet_source = label;
20156                    }
20157                }
20158            }
20159        }
20160        match Snippet::parse(&snippet_source).log_err() {
20161            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20162            None => (None, completion.new_text.clone()),
20163        }
20164    } else {
20165        (None, completion.new_text.clone())
20166    };
20167
20168    let mut range_to_replace = {
20169        let replace_range = &completion.replace_range;
20170        if let CompletionSource::Lsp {
20171            insert_range: Some(insert_range),
20172            ..
20173        } = &completion.source
20174        {
20175            debug_assert_eq!(
20176                insert_range.start, replace_range.start,
20177                "insert_range and replace_range should start at the same position"
20178            );
20179            debug_assert!(
20180                insert_range
20181                    .start
20182                    .cmp(&cursor_position, &buffer_snapshot)
20183                    .is_le(),
20184                "insert_range should start before or at cursor position"
20185            );
20186            debug_assert!(
20187                replace_range
20188                    .start
20189                    .cmp(&cursor_position, &buffer_snapshot)
20190                    .is_le(),
20191                "replace_range should start before or at cursor position"
20192            );
20193            debug_assert!(
20194                insert_range
20195                    .end
20196                    .cmp(&cursor_position, &buffer_snapshot)
20197                    .is_le(),
20198                "insert_range should end before or at cursor position"
20199            );
20200
20201            let should_replace = match intent {
20202                CompletionIntent::CompleteWithInsert => false,
20203                CompletionIntent::CompleteWithReplace => true,
20204                CompletionIntent::Complete | CompletionIntent::Compose => {
20205                    let insert_mode =
20206                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20207                            .completions
20208                            .lsp_insert_mode;
20209                    match insert_mode {
20210                        LspInsertMode::Insert => false,
20211                        LspInsertMode::Replace => true,
20212                        LspInsertMode::ReplaceSubsequence => {
20213                            let mut text_to_replace = buffer.chars_for_range(
20214                                buffer.anchor_before(replace_range.start)
20215                                    ..buffer.anchor_after(replace_range.end),
20216                            );
20217                            let mut current_needle = text_to_replace.next();
20218                            for haystack_ch in completion.label.text.chars() {
20219                                if let Some(needle_ch) = current_needle {
20220                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20221                                        current_needle = text_to_replace.next();
20222                                    }
20223                                }
20224                            }
20225                            current_needle.is_none()
20226                        }
20227                        LspInsertMode::ReplaceSuffix => {
20228                            if replace_range
20229                                .end
20230                                .cmp(&cursor_position, &buffer_snapshot)
20231                                .is_gt()
20232                            {
20233                                let range_after_cursor = *cursor_position..replace_range.end;
20234                                let text_after_cursor = buffer
20235                                    .text_for_range(
20236                                        buffer.anchor_before(range_after_cursor.start)
20237                                            ..buffer.anchor_after(range_after_cursor.end),
20238                                    )
20239                                    .collect::<String>()
20240                                    .to_ascii_lowercase();
20241                                completion
20242                                    .label
20243                                    .text
20244                                    .to_ascii_lowercase()
20245                                    .ends_with(&text_after_cursor)
20246                            } else {
20247                                true
20248                            }
20249                        }
20250                    }
20251                }
20252            };
20253
20254            if should_replace {
20255                replace_range.clone()
20256            } else {
20257                insert_range.clone()
20258            }
20259        } else {
20260            replace_range.clone()
20261        }
20262    };
20263
20264    if range_to_replace
20265        .end
20266        .cmp(&cursor_position, &buffer_snapshot)
20267        .is_lt()
20268    {
20269        range_to_replace.end = *cursor_position;
20270    }
20271
20272    CompletionEdit {
20273        new_text,
20274        replace_range: range_to_replace.to_offset(&buffer),
20275        snippet,
20276    }
20277}
20278
20279struct CompletionEdit {
20280    new_text: String,
20281    replace_range: Range<usize>,
20282    snippet: Option<Snippet>,
20283}
20284
20285fn insert_extra_newline_brackets(
20286    buffer: &MultiBufferSnapshot,
20287    range: Range<usize>,
20288    language: &language::LanguageScope,
20289) -> bool {
20290    let leading_whitespace_len = buffer
20291        .reversed_chars_at(range.start)
20292        .take_while(|c| c.is_whitespace() && *c != '\n')
20293        .map(|c| c.len_utf8())
20294        .sum::<usize>();
20295    let trailing_whitespace_len = buffer
20296        .chars_at(range.end)
20297        .take_while(|c| c.is_whitespace() && *c != '\n')
20298        .map(|c| c.len_utf8())
20299        .sum::<usize>();
20300    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20301
20302    language.brackets().any(|(pair, enabled)| {
20303        let pair_start = pair.start.trim_end();
20304        let pair_end = pair.end.trim_start();
20305
20306        enabled
20307            && pair.newline
20308            && buffer.contains_str_at(range.end, pair_end)
20309            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20310    })
20311}
20312
20313fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20314    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20315        [(buffer, range, _)] => (*buffer, range.clone()),
20316        _ => return false,
20317    };
20318    let pair = {
20319        let mut result: Option<BracketMatch> = None;
20320
20321        for pair in buffer
20322            .all_bracket_ranges(range.clone())
20323            .filter(move |pair| {
20324                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20325            })
20326        {
20327            let len = pair.close_range.end - pair.open_range.start;
20328
20329            if let Some(existing) = &result {
20330                let existing_len = existing.close_range.end - existing.open_range.start;
20331                if len > existing_len {
20332                    continue;
20333                }
20334            }
20335
20336            result = Some(pair);
20337        }
20338
20339        result
20340    };
20341    let Some(pair) = pair else {
20342        return false;
20343    };
20344    pair.newline_only
20345        && buffer
20346            .chars_for_range(pair.open_range.end..range.start)
20347            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20348            .all(|c| c.is_whitespace() && c != '\n')
20349}
20350
20351fn update_uncommitted_diff_for_buffer(
20352    editor: Entity<Editor>,
20353    project: &Entity<Project>,
20354    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20355    buffer: Entity<MultiBuffer>,
20356    cx: &mut App,
20357) -> Task<()> {
20358    let mut tasks = Vec::new();
20359    project.update(cx, |project, cx| {
20360        for buffer in buffers {
20361            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20362                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20363            }
20364        }
20365    });
20366    cx.spawn(async move |cx| {
20367        let diffs = future::join_all(tasks).await;
20368        if editor
20369            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20370            .unwrap_or(false)
20371        {
20372            return;
20373        }
20374
20375        buffer
20376            .update(cx, |buffer, cx| {
20377                for diff in diffs.into_iter().flatten() {
20378                    buffer.add_diff(diff, cx);
20379                }
20380            })
20381            .ok();
20382    })
20383}
20384
20385fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20386    let tab_size = tab_size.get() as usize;
20387    let mut width = offset;
20388
20389    for ch in text.chars() {
20390        width += if ch == '\t' {
20391            tab_size - (width % tab_size)
20392        } else {
20393            1
20394        };
20395    }
20396
20397    width - offset
20398}
20399
20400#[cfg(test)]
20401mod tests {
20402    use super::*;
20403
20404    #[test]
20405    fn test_string_size_with_expanded_tabs() {
20406        let nz = |val| NonZeroU32::new(val).unwrap();
20407        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20408        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20409        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20410        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20411        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20412        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20413        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20414        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20415    }
20416}
20417
20418/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20419struct WordBreakingTokenizer<'a> {
20420    input: &'a str,
20421}
20422
20423impl<'a> WordBreakingTokenizer<'a> {
20424    fn new(input: &'a str) -> Self {
20425        Self { input }
20426    }
20427}
20428
20429fn is_char_ideographic(ch: char) -> bool {
20430    use unicode_script::Script::*;
20431    use unicode_script::UnicodeScript;
20432    matches!(ch.script(), Han | Tangut | Yi)
20433}
20434
20435fn is_grapheme_ideographic(text: &str) -> bool {
20436    text.chars().any(is_char_ideographic)
20437}
20438
20439fn is_grapheme_whitespace(text: &str) -> bool {
20440    text.chars().any(|x| x.is_whitespace())
20441}
20442
20443fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20444    text.chars().next().map_or(false, |ch| {
20445        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20446    })
20447}
20448
20449#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20450enum WordBreakToken<'a> {
20451    Word { token: &'a str, grapheme_len: usize },
20452    InlineWhitespace { token: &'a str, grapheme_len: usize },
20453    Newline,
20454}
20455
20456impl<'a> Iterator for WordBreakingTokenizer<'a> {
20457    /// Yields a span, the count of graphemes in the token, and whether it was
20458    /// whitespace. Note that it also breaks at word boundaries.
20459    type Item = WordBreakToken<'a>;
20460
20461    fn next(&mut self) -> Option<Self::Item> {
20462        use unicode_segmentation::UnicodeSegmentation;
20463        if self.input.is_empty() {
20464            return None;
20465        }
20466
20467        let mut iter = self.input.graphemes(true).peekable();
20468        let mut offset = 0;
20469        let mut grapheme_len = 0;
20470        if let Some(first_grapheme) = iter.next() {
20471            let is_newline = first_grapheme == "\n";
20472            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20473            offset += first_grapheme.len();
20474            grapheme_len += 1;
20475            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20476                if let Some(grapheme) = iter.peek().copied() {
20477                    if should_stay_with_preceding_ideograph(grapheme) {
20478                        offset += grapheme.len();
20479                        grapheme_len += 1;
20480                    }
20481                }
20482            } else {
20483                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20484                let mut next_word_bound = words.peek().copied();
20485                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20486                    next_word_bound = words.next();
20487                }
20488                while let Some(grapheme) = iter.peek().copied() {
20489                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20490                        break;
20491                    };
20492                    if is_grapheme_whitespace(grapheme) != is_whitespace
20493                        || (grapheme == "\n") != is_newline
20494                    {
20495                        break;
20496                    };
20497                    offset += grapheme.len();
20498                    grapheme_len += 1;
20499                    iter.next();
20500                }
20501            }
20502            let token = &self.input[..offset];
20503            self.input = &self.input[offset..];
20504            if token == "\n" {
20505                Some(WordBreakToken::Newline)
20506            } else if is_whitespace {
20507                Some(WordBreakToken::InlineWhitespace {
20508                    token,
20509                    grapheme_len,
20510                })
20511            } else {
20512                Some(WordBreakToken::Word {
20513                    token,
20514                    grapheme_len,
20515                })
20516            }
20517        } else {
20518            None
20519        }
20520    }
20521}
20522
20523#[test]
20524fn test_word_breaking_tokenizer() {
20525    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20526        ("", &[]),
20527        ("  ", &[whitespace("  ", 2)]),
20528        ("Ʒ", &[word("Ʒ", 1)]),
20529        ("Ǽ", &[word("Ǽ", 1)]),
20530        ("", &[word("", 1)]),
20531        ("⋑⋑", &[word("⋑⋑", 2)]),
20532        (
20533            "原理,进而",
20534            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20535        ),
20536        (
20537            "hello world",
20538            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20539        ),
20540        (
20541            "hello, world",
20542            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20543        ),
20544        (
20545            "  hello world",
20546            &[
20547                whitespace("  ", 2),
20548                word("hello", 5),
20549                whitespace(" ", 1),
20550                word("world", 5),
20551            ],
20552        ),
20553        (
20554            "这是什么 \n 钢笔",
20555            &[
20556                word("", 1),
20557                word("", 1),
20558                word("", 1),
20559                word("", 1),
20560                whitespace(" ", 1),
20561                newline(),
20562                whitespace(" ", 1),
20563                word("", 1),
20564                word("", 1),
20565            ],
20566        ),
20567        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20568    ];
20569
20570    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20571        WordBreakToken::Word {
20572            token,
20573            grapheme_len,
20574        }
20575    }
20576
20577    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20578        WordBreakToken::InlineWhitespace {
20579            token,
20580            grapheme_len,
20581        }
20582    }
20583
20584    fn newline() -> WordBreakToken<'static> {
20585        WordBreakToken::Newline
20586    }
20587
20588    for (input, result) in tests {
20589        assert_eq!(
20590            WordBreakingTokenizer::new(input)
20591                .collect::<Vec<_>>()
20592                .as_slice(),
20593            *result,
20594        );
20595    }
20596}
20597
20598fn wrap_with_prefix(
20599    line_prefix: String,
20600    unwrapped_text: String,
20601    wrap_column: usize,
20602    tab_size: NonZeroU32,
20603    preserve_existing_whitespace: bool,
20604) -> String {
20605    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20606    let mut wrapped_text = String::new();
20607    let mut current_line = line_prefix.clone();
20608
20609    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20610    let mut current_line_len = line_prefix_len;
20611    let mut in_whitespace = false;
20612    for token in tokenizer {
20613        let have_preceding_whitespace = in_whitespace;
20614        match token {
20615            WordBreakToken::Word {
20616                token,
20617                grapheme_len,
20618            } => {
20619                in_whitespace = false;
20620                if current_line_len + grapheme_len > wrap_column
20621                    && current_line_len != line_prefix_len
20622                {
20623                    wrapped_text.push_str(current_line.trim_end());
20624                    wrapped_text.push('\n');
20625                    current_line.truncate(line_prefix.len());
20626                    current_line_len = line_prefix_len;
20627                }
20628                current_line.push_str(token);
20629                current_line_len += grapheme_len;
20630            }
20631            WordBreakToken::InlineWhitespace {
20632                mut token,
20633                mut grapheme_len,
20634            } => {
20635                in_whitespace = true;
20636                if have_preceding_whitespace && !preserve_existing_whitespace {
20637                    continue;
20638                }
20639                if !preserve_existing_whitespace {
20640                    token = " ";
20641                    grapheme_len = 1;
20642                }
20643                if current_line_len + grapheme_len > wrap_column {
20644                    wrapped_text.push_str(current_line.trim_end());
20645                    wrapped_text.push('\n');
20646                    current_line.truncate(line_prefix.len());
20647                    current_line_len = line_prefix_len;
20648                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20649                    current_line.push_str(token);
20650                    current_line_len += grapheme_len;
20651                }
20652            }
20653            WordBreakToken::Newline => {
20654                in_whitespace = true;
20655                if preserve_existing_whitespace {
20656                    wrapped_text.push_str(current_line.trim_end());
20657                    wrapped_text.push('\n');
20658                    current_line.truncate(line_prefix.len());
20659                    current_line_len = line_prefix_len;
20660                } else if have_preceding_whitespace {
20661                    continue;
20662                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20663                {
20664                    wrapped_text.push_str(current_line.trim_end());
20665                    wrapped_text.push('\n');
20666                    current_line.truncate(line_prefix.len());
20667                    current_line_len = line_prefix_len;
20668                } else if current_line_len != line_prefix_len {
20669                    current_line.push(' ');
20670                    current_line_len += 1;
20671                }
20672            }
20673        }
20674    }
20675
20676    if !current_line.is_empty() {
20677        wrapped_text.push_str(&current_line);
20678    }
20679    wrapped_text
20680}
20681
20682#[test]
20683fn test_wrap_with_prefix() {
20684    assert_eq!(
20685        wrap_with_prefix(
20686            "# ".to_string(),
20687            "abcdefg".to_string(),
20688            4,
20689            NonZeroU32::new(4).unwrap(),
20690            false,
20691        ),
20692        "# abcdefg"
20693    );
20694    assert_eq!(
20695        wrap_with_prefix(
20696            "".to_string(),
20697            "\thello world".to_string(),
20698            8,
20699            NonZeroU32::new(4).unwrap(),
20700            false,
20701        ),
20702        "hello\nworld"
20703    );
20704    assert_eq!(
20705        wrap_with_prefix(
20706            "// ".to_string(),
20707            "xx \nyy zz aa bb cc".to_string(),
20708            12,
20709            NonZeroU32::new(4).unwrap(),
20710            false,
20711        ),
20712        "// xx yy zz\n// aa bb cc"
20713    );
20714    assert_eq!(
20715        wrap_with_prefix(
20716            String::new(),
20717            "这是什么 \n 钢笔".to_string(),
20718            3,
20719            NonZeroU32::new(4).unwrap(),
20720            false,
20721        ),
20722        "这是什\n么 钢\n"
20723    );
20724}
20725
20726pub trait CollaborationHub {
20727    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20728    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20729    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20730}
20731
20732impl CollaborationHub for Entity<Project> {
20733    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20734        self.read(cx).collaborators()
20735    }
20736
20737    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20738        self.read(cx).user_store().read(cx).participant_indices()
20739    }
20740
20741    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20742        let this = self.read(cx);
20743        let user_ids = this.collaborators().values().map(|c| c.user_id);
20744        this.user_store().read(cx).participant_names(user_ids, cx)
20745    }
20746}
20747
20748pub trait SemanticsProvider {
20749    fn hover(
20750        &self,
20751        buffer: &Entity<Buffer>,
20752        position: text::Anchor,
20753        cx: &mut App,
20754    ) -> Option<Task<Vec<project::Hover>>>;
20755
20756    fn inline_values(
20757        &self,
20758        buffer_handle: Entity<Buffer>,
20759        range: Range<text::Anchor>,
20760        cx: &mut App,
20761    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20762
20763    fn inlay_hints(
20764        &self,
20765        buffer_handle: Entity<Buffer>,
20766        range: Range<text::Anchor>,
20767        cx: &mut App,
20768    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20769
20770    fn resolve_inlay_hint(
20771        &self,
20772        hint: InlayHint,
20773        buffer_handle: Entity<Buffer>,
20774        server_id: LanguageServerId,
20775        cx: &mut App,
20776    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20777
20778    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20779
20780    fn document_highlights(
20781        &self,
20782        buffer: &Entity<Buffer>,
20783        position: text::Anchor,
20784        cx: &mut App,
20785    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20786
20787    fn definitions(
20788        &self,
20789        buffer: &Entity<Buffer>,
20790        position: text::Anchor,
20791        kind: GotoDefinitionKind,
20792        cx: &mut App,
20793    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20794
20795    fn range_for_rename(
20796        &self,
20797        buffer: &Entity<Buffer>,
20798        position: text::Anchor,
20799        cx: &mut App,
20800    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20801
20802    fn perform_rename(
20803        &self,
20804        buffer: &Entity<Buffer>,
20805        position: text::Anchor,
20806        new_name: String,
20807        cx: &mut App,
20808    ) -> Option<Task<Result<ProjectTransaction>>>;
20809
20810    fn pull_diagnostics_for_buffer(
20811        &self,
20812        buffer: Entity<Buffer>,
20813        cx: &mut App,
20814    ) -> Task<anyhow::Result<()>>;
20815}
20816
20817pub trait CompletionProvider {
20818    fn completions(
20819        &self,
20820        excerpt_id: ExcerptId,
20821        buffer: &Entity<Buffer>,
20822        buffer_position: text::Anchor,
20823        trigger: CompletionContext,
20824        window: &mut Window,
20825        cx: &mut Context<Editor>,
20826    ) -> Task<Result<Vec<CompletionResponse>>>;
20827
20828    fn resolve_completions(
20829        &self,
20830        _buffer: Entity<Buffer>,
20831        _completion_indices: Vec<usize>,
20832        _completions: Rc<RefCell<Box<[Completion]>>>,
20833        _cx: &mut Context<Editor>,
20834    ) -> Task<Result<bool>> {
20835        Task::ready(Ok(false))
20836    }
20837
20838    fn apply_additional_edits_for_completion(
20839        &self,
20840        _buffer: Entity<Buffer>,
20841        _completions: Rc<RefCell<Box<[Completion]>>>,
20842        _completion_index: usize,
20843        _push_to_history: bool,
20844        _cx: &mut Context<Editor>,
20845    ) -> Task<Result<Option<language::Transaction>>> {
20846        Task::ready(Ok(None))
20847    }
20848
20849    fn is_completion_trigger(
20850        &self,
20851        buffer: &Entity<Buffer>,
20852        position: language::Anchor,
20853        text: &str,
20854        trigger_in_words: bool,
20855        menu_is_open: bool,
20856        cx: &mut Context<Editor>,
20857    ) -> bool;
20858
20859    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20860
20861    fn sort_completions(&self) -> bool {
20862        true
20863    }
20864
20865    fn filter_completions(&self) -> bool {
20866        true
20867    }
20868}
20869
20870pub trait CodeActionProvider {
20871    fn id(&self) -> Arc<str>;
20872
20873    fn code_actions(
20874        &self,
20875        buffer: &Entity<Buffer>,
20876        range: Range<text::Anchor>,
20877        window: &mut Window,
20878        cx: &mut App,
20879    ) -> Task<Result<Vec<CodeAction>>>;
20880
20881    fn apply_code_action(
20882        &self,
20883        buffer_handle: Entity<Buffer>,
20884        action: CodeAction,
20885        excerpt_id: ExcerptId,
20886        push_to_history: bool,
20887        window: &mut Window,
20888        cx: &mut App,
20889    ) -> Task<Result<ProjectTransaction>>;
20890}
20891
20892impl CodeActionProvider for Entity<Project> {
20893    fn id(&self) -> Arc<str> {
20894        "project".into()
20895    }
20896
20897    fn code_actions(
20898        &self,
20899        buffer: &Entity<Buffer>,
20900        range: Range<text::Anchor>,
20901        _window: &mut Window,
20902        cx: &mut App,
20903    ) -> Task<Result<Vec<CodeAction>>> {
20904        self.update(cx, |project, cx| {
20905            let code_lens = project.code_lens(buffer, range.clone(), cx);
20906            let code_actions = project.code_actions(buffer, range, None, cx);
20907            cx.background_spawn(async move {
20908                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20909                Ok(code_lens
20910                    .context("code lens fetch")?
20911                    .into_iter()
20912                    .chain(code_actions.context("code action fetch")?)
20913                    .collect())
20914            })
20915        })
20916    }
20917
20918    fn apply_code_action(
20919        &self,
20920        buffer_handle: Entity<Buffer>,
20921        action: CodeAction,
20922        _excerpt_id: ExcerptId,
20923        push_to_history: bool,
20924        _window: &mut Window,
20925        cx: &mut App,
20926    ) -> Task<Result<ProjectTransaction>> {
20927        self.update(cx, |project, cx| {
20928            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20929        })
20930    }
20931}
20932
20933fn snippet_completions(
20934    project: &Project,
20935    buffer: &Entity<Buffer>,
20936    buffer_position: text::Anchor,
20937    cx: &mut App,
20938) -> Task<Result<CompletionResponse>> {
20939    let languages = buffer.read(cx).languages_at(buffer_position);
20940    let snippet_store = project.snippets().read(cx);
20941
20942    let scopes: Vec<_> = languages
20943        .iter()
20944        .filter_map(|language| {
20945            let language_name = language.lsp_id();
20946            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20947
20948            if snippets.is_empty() {
20949                None
20950            } else {
20951                Some((language.default_scope(), snippets))
20952            }
20953        })
20954        .collect();
20955
20956    if scopes.is_empty() {
20957        return Task::ready(Ok(CompletionResponse {
20958            completions: vec![],
20959            is_incomplete: false,
20960        }));
20961    }
20962
20963    let snapshot = buffer.read(cx).text_snapshot();
20964    let chars: String = snapshot
20965        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20966        .collect();
20967    let executor = cx.background_executor().clone();
20968
20969    cx.background_spawn(async move {
20970        let mut is_incomplete = false;
20971        let mut completions: Vec<Completion> = Vec::new();
20972        for (scope, snippets) in scopes.into_iter() {
20973            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20974            let mut last_word = chars
20975                .chars()
20976                .take_while(|c| classifier.is_word(*c))
20977                .collect::<String>();
20978            last_word = last_word.chars().rev().collect();
20979
20980            if last_word.is_empty() {
20981                return Ok(CompletionResponse {
20982                    completions: vec![],
20983                    is_incomplete: true,
20984                });
20985            }
20986
20987            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20988            let to_lsp = |point: &text::Anchor| {
20989                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20990                point_to_lsp(end)
20991            };
20992            let lsp_end = to_lsp(&buffer_position);
20993
20994            let candidates = snippets
20995                .iter()
20996                .enumerate()
20997                .flat_map(|(ix, snippet)| {
20998                    snippet
20999                        .prefix
21000                        .iter()
21001                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21002                })
21003                .collect::<Vec<StringMatchCandidate>>();
21004
21005            const MAX_RESULTS: usize = 100;
21006            let mut matches = fuzzy::match_strings(
21007                &candidates,
21008                &last_word,
21009                last_word.chars().any(|c| c.is_uppercase()),
21010                MAX_RESULTS,
21011                &Default::default(),
21012                executor.clone(),
21013            )
21014            .await;
21015
21016            if matches.len() >= MAX_RESULTS {
21017                is_incomplete = true;
21018            }
21019
21020            // Remove all candidates where the query's start does not match the start of any word in the candidate
21021            if let Some(query_start) = last_word.chars().next() {
21022                matches.retain(|string_match| {
21023                    split_words(&string_match.string).any(|word| {
21024                        // Check that the first codepoint of the word as lowercase matches the first
21025                        // codepoint of the query as lowercase
21026                        word.chars()
21027                            .flat_map(|codepoint| codepoint.to_lowercase())
21028                            .zip(query_start.to_lowercase())
21029                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21030                    })
21031                });
21032            }
21033
21034            let matched_strings = matches
21035                .into_iter()
21036                .map(|m| m.string)
21037                .collect::<HashSet<_>>();
21038
21039            completions.extend(snippets.iter().filter_map(|snippet| {
21040                let matching_prefix = snippet
21041                    .prefix
21042                    .iter()
21043                    .find(|prefix| matched_strings.contains(*prefix))?;
21044                let start = as_offset - last_word.len();
21045                let start = snapshot.anchor_before(start);
21046                let range = start..buffer_position;
21047                let lsp_start = to_lsp(&start);
21048                let lsp_range = lsp::Range {
21049                    start: lsp_start,
21050                    end: lsp_end,
21051                };
21052                Some(Completion {
21053                    replace_range: range,
21054                    new_text: snippet.body.clone(),
21055                    source: CompletionSource::Lsp {
21056                        insert_range: None,
21057                        server_id: LanguageServerId(usize::MAX),
21058                        resolved: true,
21059                        lsp_completion: Box::new(lsp::CompletionItem {
21060                            label: snippet.prefix.first().unwrap().clone(),
21061                            kind: Some(CompletionItemKind::SNIPPET),
21062                            label_details: snippet.description.as_ref().map(|description| {
21063                                lsp::CompletionItemLabelDetails {
21064                                    detail: Some(description.clone()),
21065                                    description: None,
21066                                }
21067                            }),
21068                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21069                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21070                                lsp::InsertReplaceEdit {
21071                                    new_text: snippet.body.clone(),
21072                                    insert: lsp_range,
21073                                    replace: lsp_range,
21074                                },
21075                            )),
21076                            filter_text: Some(snippet.body.clone()),
21077                            sort_text: Some(char::MAX.to_string()),
21078                            ..lsp::CompletionItem::default()
21079                        }),
21080                        lsp_defaults: None,
21081                    },
21082                    label: CodeLabel {
21083                        text: matching_prefix.clone(),
21084                        runs: Vec::new(),
21085                        filter_range: 0..matching_prefix.len(),
21086                    },
21087                    icon_path: None,
21088                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21089                        single_line: snippet.name.clone().into(),
21090                        plain_text: snippet
21091                            .description
21092                            .clone()
21093                            .map(|description| description.into()),
21094                    }),
21095                    insert_text_mode: None,
21096                    confirm: None,
21097                })
21098            }))
21099        }
21100
21101        Ok(CompletionResponse {
21102            completions,
21103            is_incomplete,
21104        })
21105    })
21106}
21107
21108impl CompletionProvider for Entity<Project> {
21109    fn completions(
21110        &self,
21111        _excerpt_id: ExcerptId,
21112        buffer: &Entity<Buffer>,
21113        buffer_position: text::Anchor,
21114        options: CompletionContext,
21115        _window: &mut Window,
21116        cx: &mut Context<Editor>,
21117    ) -> Task<Result<Vec<CompletionResponse>>> {
21118        self.update(cx, |project, cx| {
21119            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21120            let project_completions = project.completions(buffer, buffer_position, options, cx);
21121            cx.background_spawn(async move {
21122                let mut responses = project_completions.await?;
21123                let snippets = snippets.await?;
21124                if !snippets.completions.is_empty() {
21125                    responses.push(snippets);
21126                }
21127                Ok(responses)
21128            })
21129        })
21130    }
21131
21132    fn resolve_completions(
21133        &self,
21134        buffer: Entity<Buffer>,
21135        completion_indices: Vec<usize>,
21136        completions: Rc<RefCell<Box<[Completion]>>>,
21137        cx: &mut Context<Editor>,
21138    ) -> Task<Result<bool>> {
21139        self.update(cx, |project, cx| {
21140            project.lsp_store().update(cx, |lsp_store, cx| {
21141                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21142            })
21143        })
21144    }
21145
21146    fn apply_additional_edits_for_completion(
21147        &self,
21148        buffer: Entity<Buffer>,
21149        completions: Rc<RefCell<Box<[Completion]>>>,
21150        completion_index: usize,
21151        push_to_history: bool,
21152        cx: &mut Context<Editor>,
21153    ) -> Task<Result<Option<language::Transaction>>> {
21154        self.update(cx, |project, cx| {
21155            project.lsp_store().update(cx, |lsp_store, cx| {
21156                lsp_store.apply_additional_edits_for_completion(
21157                    buffer,
21158                    completions,
21159                    completion_index,
21160                    push_to_history,
21161                    cx,
21162                )
21163            })
21164        })
21165    }
21166
21167    fn is_completion_trigger(
21168        &self,
21169        buffer: &Entity<Buffer>,
21170        position: language::Anchor,
21171        text: &str,
21172        trigger_in_words: bool,
21173        menu_is_open: bool,
21174        cx: &mut Context<Editor>,
21175    ) -> bool {
21176        let mut chars = text.chars();
21177        let char = if let Some(char) = chars.next() {
21178            char
21179        } else {
21180            return false;
21181        };
21182        if chars.next().is_some() {
21183            return false;
21184        }
21185
21186        let buffer = buffer.read(cx);
21187        let snapshot = buffer.snapshot();
21188        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21189            return false;
21190        }
21191        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21192        if trigger_in_words && classifier.is_word(char) {
21193            return true;
21194        }
21195
21196        buffer.completion_triggers().contains(text)
21197    }
21198}
21199
21200impl SemanticsProvider for Entity<Project> {
21201    fn hover(
21202        &self,
21203        buffer: &Entity<Buffer>,
21204        position: text::Anchor,
21205        cx: &mut App,
21206    ) -> Option<Task<Vec<project::Hover>>> {
21207        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21208    }
21209
21210    fn document_highlights(
21211        &self,
21212        buffer: &Entity<Buffer>,
21213        position: text::Anchor,
21214        cx: &mut App,
21215    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21216        Some(self.update(cx, |project, cx| {
21217            project.document_highlights(buffer, position, cx)
21218        }))
21219    }
21220
21221    fn definitions(
21222        &self,
21223        buffer: &Entity<Buffer>,
21224        position: text::Anchor,
21225        kind: GotoDefinitionKind,
21226        cx: &mut App,
21227    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21228        Some(self.update(cx, |project, cx| match kind {
21229            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21230            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21231            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21232            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21233        }))
21234    }
21235
21236    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21237        // TODO: make this work for remote projects
21238        self.update(cx, |project, cx| {
21239            if project
21240                .active_debug_session(cx)
21241                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21242            {
21243                return true;
21244            }
21245
21246            buffer.update(cx, |buffer, cx| {
21247                project.any_language_server_supports_inlay_hints(buffer, cx)
21248            })
21249        })
21250    }
21251
21252    fn inline_values(
21253        &self,
21254        buffer_handle: Entity<Buffer>,
21255
21256        range: Range<text::Anchor>,
21257        cx: &mut App,
21258    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21259        self.update(cx, |project, cx| {
21260            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21261
21262            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21263        })
21264    }
21265
21266    fn inlay_hints(
21267        &self,
21268        buffer_handle: Entity<Buffer>,
21269        range: Range<text::Anchor>,
21270        cx: &mut App,
21271    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21272        Some(self.update(cx, |project, cx| {
21273            project.inlay_hints(buffer_handle, range, cx)
21274        }))
21275    }
21276
21277    fn resolve_inlay_hint(
21278        &self,
21279        hint: InlayHint,
21280        buffer_handle: Entity<Buffer>,
21281        server_id: LanguageServerId,
21282        cx: &mut App,
21283    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21284        Some(self.update(cx, |project, cx| {
21285            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21286        }))
21287    }
21288
21289    fn range_for_rename(
21290        &self,
21291        buffer: &Entity<Buffer>,
21292        position: text::Anchor,
21293        cx: &mut App,
21294    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21295        Some(self.update(cx, |project, cx| {
21296            let buffer = buffer.clone();
21297            let task = project.prepare_rename(buffer.clone(), position, cx);
21298            cx.spawn(async move |_, cx| {
21299                Ok(match task.await? {
21300                    PrepareRenameResponse::Success(range) => Some(range),
21301                    PrepareRenameResponse::InvalidPosition => None,
21302                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21303                        // Fallback on using TreeSitter info to determine identifier range
21304                        buffer.read_with(cx, |buffer, _| {
21305                            let snapshot = buffer.snapshot();
21306                            let (range, kind) = snapshot.surrounding_word(position);
21307                            if kind != Some(CharKind::Word) {
21308                                return None;
21309                            }
21310                            Some(
21311                                snapshot.anchor_before(range.start)
21312                                    ..snapshot.anchor_after(range.end),
21313                            )
21314                        })?
21315                    }
21316                })
21317            })
21318        }))
21319    }
21320
21321    fn perform_rename(
21322        &self,
21323        buffer: &Entity<Buffer>,
21324        position: text::Anchor,
21325        new_name: String,
21326        cx: &mut App,
21327    ) -> Option<Task<Result<ProjectTransaction>>> {
21328        Some(self.update(cx, |project, cx| {
21329            project.perform_rename(buffer.clone(), position, new_name, cx)
21330        }))
21331    }
21332
21333    fn pull_diagnostics_for_buffer(
21334        &self,
21335        buffer: Entity<Buffer>,
21336        cx: &mut App,
21337    ) -> Task<anyhow::Result<()>> {
21338        let diagnostics = self.update(cx, |project, cx| {
21339            project
21340                .lsp_store()
21341                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21342        });
21343        let project = self.clone();
21344        cx.spawn(async move |cx| {
21345            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21346            project.update(cx, |project, cx| {
21347                project.lsp_store().update(cx, |lsp_store, cx| {
21348                    for diagnostics_set in diagnostics {
21349                        let LspPullDiagnostics::Response {
21350                            server_id,
21351                            uri,
21352                            diagnostics,
21353                        } = diagnostics_set
21354                        else {
21355                            continue;
21356                        };
21357
21358                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21359                        let disk_based_sources = adapter
21360                            .as_ref()
21361                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21362                            .unwrap_or(&[]);
21363                        match diagnostics {
21364                            PulledDiagnostics::Unchanged { result_id } => {
21365                                lsp_store
21366                                    .merge_diagnostics(
21367                                        server_id,
21368                                        lsp::PublishDiagnosticsParams {
21369                                            uri: uri.clone(),
21370                                            diagnostics: Vec::new(),
21371                                            version: None,
21372                                        },
21373                                        Some(result_id),
21374                                        DiagnosticSourceKind::Pulled,
21375                                        disk_based_sources,
21376                                        |_, _| true,
21377                                        cx,
21378                                    )
21379                                    .log_err();
21380                            }
21381                            PulledDiagnostics::Changed {
21382                                diagnostics,
21383                                result_id,
21384                            } => {
21385                                lsp_store
21386                                    .merge_diagnostics(
21387                                        server_id,
21388                                        lsp::PublishDiagnosticsParams {
21389                                            uri: uri.clone(),
21390                                            diagnostics,
21391                                            version: None,
21392                                        },
21393                                        result_id,
21394                                        DiagnosticSourceKind::Pulled,
21395                                        disk_based_sources,
21396                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21397                                            DiagnosticSourceKind::Pulled => false,
21398                                            DiagnosticSourceKind::Other
21399                                            | DiagnosticSourceKind::Pushed => true,
21400                                        },
21401                                        cx,
21402                                    )
21403                                    .log_err();
21404                            }
21405                        }
21406                    }
21407                })
21408            })
21409        })
21410    }
21411}
21412
21413fn inlay_hint_settings(
21414    location: Anchor,
21415    snapshot: &MultiBufferSnapshot,
21416    cx: &mut Context<Editor>,
21417) -> InlayHintSettings {
21418    let file = snapshot.file_at(location);
21419    let language = snapshot.language_at(location).map(|l| l.name());
21420    language_settings(language, file, cx).inlay_hints
21421}
21422
21423fn consume_contiguous_rows(
21424    contiguous_row_selections: &mut Vec<Selection<Point>>,
21425    selection: &Selection<Point>,
21426    display_map: &DisplaySnapshot,
21427    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21428) -> (MultiBufferRow, MultiBufferRow) {
21429    contiguous_row_selections.push(selection.clone());
21430    let start_row = MultiBufferRow(selection.start.row);
21431    let mut end_row = ending_row(selection, display_map);
21432
21433    while let Some(next_selection) = selections.peek() {
21434        if next_selection.start.row <= end_row.0 {
21435            end_row = ending_row(next_selection, display_map);
21436            contiguous_row_selections.push(selections.next().unwrap().clone());
21437        } else {
21438            break;
21439        }
21440    }
21441    (start_row, end_row)
21442}
21443
21444fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21445    if next_selection.end.column > 0 || next_selection.is_empty() {
21446        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21447    } else {
21448        MultiBufferRow(next_selection.end.row)
21449    }
21450}
21451
21452impl EditorSnapshot {
21453    pub fn remote_selections_in_range<'a>(
21454        &'a self,
21455        range: &'a Range<Anchor>,
21456        collaboration_hub: &dyn CollaborationHub,
21457        cx: &'a App,
21458    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21459        let participant_names = collaboration_hub.user_names(cx);
21460        let participant_indices = collaboration_hub.user_participant_indices(cx);
21461        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21462        let collaborators_by_replica_id = collaborators_by_peer_id
21463            .values()
21464            .map(|collaborator| (collaborator.replica_id, collaborator))
21465            .collect::<HashMap<_, _>>();
21466        self.buffer_snapshot
21467            .selections_in_range(range, false)
21468            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21469                if replica_id == AGENT_REPLICA_ID {
21470                    Some(RemoteSelection {
21471                        replica_id,
21472                        selection,
21473                        cursor_shape,
21474                        line_mode,
21475                        collaborator_id: CollaboratorId::Agent,
21476                        user_name: Some("Agent".into()),
21477                        color: cx.theme().players().agent(),
21478                    })
21479                } else {
21480                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21481                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21482                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21483                    Some(RemoteSelection {
21484                        replica_id,
21485                        selection,
21486                        cursor_shape,
21487                        line_mode,
21488                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21489                        user_name,
21490                        color: if let Some(index) = participant_index {
21491                            cx.theme().players().color_for_participant(index.0)
21492                        } else {
21493                            cx.theme().players().absent()
21494                        },
21495                    })
21496                }
21497            })
21498    }
21499
21500    pub fn hunks_for_ranges(
21501        &self,
21502        ranges: impl IntoIterator<Item = Range<Point>>,
21503    ) -> Vec<MultiBufferDiffHunk> {
21504        let mut hunks = Vec::new();
21505        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21506            HashMap::default();
21507        for query_range in ranges {
21508            let query_rows =
21509                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21510            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21511                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21512            ) {
21513                // Include deleted hunks that are adjacent to the query range, because
21514                // otherwise they would be missed.
21515                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21516                if hunk.status().is_deleted() {
21517                    intersects_range |= hunk.row_range.start == query_rows.end;
21518                    intersects_range |= hunk.row_range.end == query_rows.start;
21519                }
21520                if intersects_range {
21521                    if !processed_buffer_rows
21522                        .entry(hunk.buffer_id)
21523                        .or_default()
21524                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21525                    {
21526                        continue;
21527                    }
21528                    hunks.push(hunk);
21529                }
21530            }
21531        }
21532
21533        hunks
21534    }
21535
21536    fn display_diff_hunks_for_rows<'a>(
21537        &'a self,
21538        display_rows: Range<DisplayRow>,
21539        folded_buffers: &'a HashSet<BufferId>,
21540    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21541        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21542        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21543
21544        self.buffer_snapshot
21545            .diff_hunks_in_range(buffer_start..buffer_end)
21546            .filter_map(|hunk| {
21547                if folded_buffers.contains(&hunk.buffer_id) {
21548                    return None;
21549                }
21550
21551                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21552                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21553
21554                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21555                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21556
21557                let display_hunk = if hunk_display_start.column() != 0 {
21558                    DisplayDiffHunk::Folded {
21559                        display_row: hunk_display_start.row(),
21560                    }
21561                } else {
21562                    let mut end_row = hunk_display_end.row();
21563                    if hunk_display_end.column() > 0 {
21564                        end_row.0 += 1;
21565                    }
21566                    let is_created_file = hunk.is_created_file();
21567                    DisplayDiffHunk::Unfolded {
21568                        status: hunk.status(),
21569                        diff_base_byte_range: hunk.diff_base_byte_range,
21570                        display_row_range: hunk_display_start.row()..end_row,
21571                        multi_buffer_range: Anchor::range_in_buffer(
21572                            hunk.excerpt_id,
21573                            hunk.buffer_id,
21574                            hunk.buffer_range,
21575                        ),
21576                        is_created_file,
21577                    }
21578                };
21579
21580                Some(display_hunk)
21581            })
21582    }
21583
21584    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21585        self.display_snapshot.buffer_snapshot.language_at(position)
21586    }
21587
21588    pub fn is_focused(&self) -> bool {
21589        self.is_focused
21590    }
21591
21592    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21593        self.placeholder_text.as_ref()
21594    }
21595
21596    pub fn scroll_position(&self) -> gpui::Point<f32> {
21597        self.scroll_anchor.scroll_position(&self.display_snapshot)
21598    }
21599
21600    fn gutter_dimensions(
21601        &self,
21602        font_id: FontId,
21603        font_size: Pixels,
21604        max_line_number_width: Pixels,
21605        cx: &App,
21606    ) -> Option<GutterDimensions> {
21607        if !self.show_gutter {
21608            return None;
21609        }
21610
21611        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21612        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21613
21614        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21615            matches!(
21616                ProjectSettings::get_global(cx).git.git_gutter,
21617                Some(GitGutterSetting::TrackedFiles)
21618            )
21619        });
21620        let gutter_settings = EditorSettings::get_global(cx).gutter;
21621        let show_line_numbers = self
21622            .show_line_numbers
21623            .unwrap_or(gutter_settings.line_numbers);
21624        let line_gutter_width = if show_line_numbers {
21625            // Avoid flicker-like gutter resizes when the line number gains another digit by
21626            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21627            let min_width_for_number_on_gutter =
21628                ch_advance * gutter_settings.min_line_number_digits as f32;
21629            max_line_number_width.max(min_width_for_number_on_gutter)
21630        } else {
21631            0.0.into()
21632        };
21633
21634        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21635        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21636
21637        let git_blame_entries_width =
21638            self.git_blame_gutter_max_author_length
21639                .map(|max_author_length| {
21640                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21641                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21642
21643                    /// The number of characters to dedicate to gaps and margins.
21644                    const SPACING_WIDTH: usize = 4;
21645
21646                    let max_char_count = max_author_length.min(renderer.max_author_length())
21647                        + ::git::SHORT_SHA_LENGTH
21648                        + MAX_RELATIVE_TIMESTAMP.len()
21649                        + SPACING_WIDTH;
21650
21651                    ch_advance * max_char_count
21652                });
21653
21654        let is_singleton = self.buffer_snapshot.is_singleton();
21655
21656        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21657        left_padding += if !is_singleton {
21658            ch_width * 4.0
21659        } else if show_runnables || show_breakpoints {
21660            ch_width * 3.0
21661        } else if show_git_gutter && show_line_numbers {
21662            ch_width * 2.0
21663        } else if show_git_gutter || show_line_numbers {
21664            ch_width
21665        } else {
21666            px(0.)
21667        };
21668
21669        let shows_folds = is_singleton && gutter_settings.folds;
21670
21671        let right_padding = if shows_folds && show_line_numbers {
21672            ch_width * 4.0
21673        } else if shows_folds || (!is_singleton && show_line_numbers) {
21674            ch_width * 3.0
21675        } else if show_line_numbers {
21676            ch_width
21677        } else {
21678            px(0.)
21679        };
21680
21681        Some(GutterDimensions {
21682            left_padding,
21683            right_padding,
21684            width: line_gutter_width + left_padding + right_padding,
21685            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21686            git_blame_entries_width,
21687        })
21688    }
21689
21690    pub fn render_crease_toggle(
21691        &self,
21692        buffer_row: MultiBufferRow,
21693        row_contains_cursor: bool,
21694        editor: Entity<Editor>,
21695        window: &mut Window,
21696        cx: &mut App,
21697    ) -> Option<AnyElement> {
21698        let folded = self.is_line_folded(buffer_row);
21699        let mut is_foldable = false;
21700
21701        if let Some(crease) = self
21702            .crease_snapshot
21703            .query_row(buffer_row, &self.buffer_snapshot)
21704        {
21705            is_foldable = true;
21706            match crease {
21707                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21708                    if let Some(render_toggle) = render_toggle {
21709                        let toggle_callback =
21710                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21711                                if folded {
21712                                    editor.update(cx, |editor, cx| {
21713                                        editor.fold_at(buffer_row, window, cx)
21714                                    });
21715                                } else {
21716                                    editor.update(cx, |editor, cx| {
21717                                        editor.unfold_at(buffer_row, window, cx)
21718                                    });
21719                                }
21720                            });
21721                        return Some((render_toggle)(
21722                            buffer_row,
21723                            folded,
21724                            toggle_callback,
21725                            window,
21726                            cx,
21727                        ));
21728                    }
21729                }
21730            }
21731        }
21732
21733        is_foldable |= self.starts_indent(buffer_row);
21734
21735        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21736            Some(
21737                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21738                    .toggle_state(folded)
21739                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21740                        if folded {
21741                            this.unfold_at(buffer_row, window, cx);
21742                        } else {
21743                            this.fold_at(buffer_row, window, cx);
21744                        }
21745                    }))
21746                    .into_any_element(),
21747            )
21748        } else {
21749            None
21750        }
21751    }
21752
21753    pub fn render_crease_trailer(
21754        &self,
21755        buffer_row: MultiBufferRow,
21756        window: &mut Window,
21757        cx: &mut App,
21758    ) -> Option<AnyElement> {
21759        let folded = self.is_line_folded(buffer_row);
21760        if let Crease::Inline { render_trailer, .. } = self
21761            .crease_snapshot
21762            .query_row(buffer_row, &self.buffer_snapshot)?
21763        {
21764            let render_trailer = render_trailer.as_ref()?;
21765            Some(render_trailer(buffer_row, folded, window, cx))
21766        } else {
21767            None
21768        }
21769    }
21770}
21771
21772impl Deref for EditorSnapshot {
21773    type Target = DisplaySnapshot;
21774
21775    fn deref(&self) -> &Self::Target {
21776        &self.display_snapshot
21777    }
21778}
21779
21780#[derive(Clone, Debug, PartialEq, Eq)]
21781pub enum EditorEvent {
21782    InputIgnored {
21783        text: Arc<str>,
21784    },
21785    InputHandled {
21786        utf16_range_to_replace: Option<Range<isize>>,
21787        text: Arc<str>,
21788    },
21789    ExcerptsAdded {
21790        buffer: Entity<Buffer>,
21791        predecessor: ExcerptId,
21792        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21793    },
21794    ExcerptsRemoved {
21795        ids: Vec<ExcerptId>,
21796        removed_buffer_ids: Vec<BufferId>,
21797    },
21798    BufferFoldToggled {
21799        ids: Vec<ExcerptId>,
21800        folded: bool,
21801    },
21802    ExcerptsEdited {
21803        ids: Vec<ExcerptId>,
21804    },
21805    ExcerptsExpanded {
21806        ids: Vec<ExcerptId>,
21807    },
21808    BufferEdited,
21809    Edited {
21810        transaction_id: clock::Lamport,
21811    },
21812    Reparsed(BufferId),
21813    Focused,
21814    FocusedIn,
21815    Blurred,
21816    DirtyChanged,
21817    Saved,
21818    TitleChanged,
21819    DiffBaseChanged,
21820    SelectionsChanged {
21821        local: bool,
21822    },
21823    ScrollPositionChanged {
21824        local: bool,
21825        autoscroll: bool,
21826    },
21827    Closed,
21828    TransactionUndone {
21829        transaction_id: clock::Lamport,
21830    },
21831    TransactionBegun {
21832        transaction_id: clock::Lamport,
21833    },
21834    Reloaded,
21835    CursorShapeChanged,
21836    PushedToNavHistory {
21837        anchor: Anchor,
21838        is_deactivate: bool,
21839    },
21840}
21841
21842impl EventEmitter<EditorEvent> for Editor {}
21843
21844impl Focusable for Editor {
21845    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21846        self.focus_handle.clone()
21847    }
21848}
21849
21850impl Render for Editor {
21851    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21852        let settings = ThemeSettings::get_global(cx);
21853
21854        let mut text_style = match self.mode {
21855            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21856                color: cx.theme().colors().editor_foreground,
21857                font_family: settings.ui_font.family.clone(),
21858                font_features: settings.ui_font.features.clone(),
21859                font_fallbacks: settings.ui_font.fallbacks.clone(),
21860                font_size: rems(0.875).into(),
21861                font_weight: settings.ui_font.weight,
21862                line_height: relative(settings.buffer_line_height.value()),
21863                ..Default::default()
21864            },
21865            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21866                color: cx.theme().colors().editor_foreground,
21867                font_family: settings.buffer_font.family.clone(),
21868                font_features: settings.buffer_font.features.clone(),
21869                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21870                font_size: settings.buffer_font_size(cx).into(),
21871                font_weight: settings.buffer_font.weight,
21872                line_height: relative(settings.buffer_line_height.value()),
21873                ..Default::default()
21874            },
21875        };
21876        if let Some(text_style_refinement) = &self.text_style_refinement {
21877            text_style.refine(text_style_refinement)
21878        }
21879
21880        let background = match self.mode {
21881            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21882            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21883            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21884            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21885        };
21886
21887        EditorElement::new(
21888            &cx.entity(),
21889            EditorStyle {
21890                background,
21891                local_player: cx.theme().players().local(),
21892                text: text_style,
21893                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21894                syntax: cx.theme().syntax().clone(),
21895                status: cx.theme().status().clone(),
21896                inlay_hints_style: make_inlay_hints_style(cx),
21897                inline_completion_styles: make_suggestion_styles(cx),
21898                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21899                show_underlines: !self.mode.is_minimap(),
21900            },
21901        )
21902    }
21903}
21904
21905impl EntityInputHandler for Editor {
21906    fn text_for_range(
21907        &mut self,
21908        range_utf16: Range<usize>,
21909        adjusted_range: &mut Option<Range<usize>>,
21910        _: &mut Window,
21911        cx: &mut Context<Self>,
21912    ) -> Option<String> {
21913        let snapshot = self.buffer.read(cx).read(cx);
21914        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21915        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21916        if (start.0..end.0) != range_utf16 {
21917            adjusted_range.replace(start.0..end.0);
21918        }
21919        Some(snapshot.text_for_range(start..end).collect())
21920    }
21921
21922    fn selected_text_range(
21923        &mut self,
21924        ignore_disabled_input: bool,
21925        _: &mut Window,
21926        cx: &mut Context<Self>,
21927    ) -> Option<UTF16Selection> {
21928        // Prevent the IME menu from appearing when holding down an alphabetic key
21929        // while input is disabled.
21930        if !ignore_disabled_input && !self.input_enabled {
21931            return None;
21932        }
21933
21934        let selection = self.selections.newest::<OffsetUtf16>(cx);
21935        let range = selection.range();
21936
21937        Some(UTF16Selection {
21938            range: range.start.0..range.end.0,
21939            reversed: selection.reversed,
21940        })
21941    }
21942
21943    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21944        let snapshot = self.buffer.read(cx).read(cx);
21945        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21946        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21947    }
21948
21949    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21950        self.clear_highlights::<InputComposition>(cx);
21951        self.ime_transaction.take();
21952    }
21953
21954    fn replace_text_in_range(
21955        &mut self,
21956        range_utf16: Option<Range<usize>>,
21957        text: &str,
21958        window: &mut Window,
21959        cx: &mut Context<Self>,
21960    ) {
21961        if !self.input_enabled {
21962            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21963            return;
21964        }
21965
21966        self.transact(window, cx, |this, window, cx| {
21967            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21968                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21969                Some(this.selection_replacement_ranges(range_utf16, cx))
21970            } else {
21971                this.marked_text_ranges(cx)
21972            };
21973
21974            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21975                let newest_selection_id = this.selections.newest_anchor().id;
21976                this.selections
21977                    .all::<OffsetUtf16>(cx)
21978                    .iter()
21979                    .zip(ranges_to_replace.iter())
21980                    .find_map(|(selection, range)| {
21981                        if selection.id == newest_selection_id {
21982                            Some(
21983                                (range.start.0 as isize - selection.head().0 as isize)
21984                                    ..(range.end.0 as isize - selection.head().0 as isize),
21985                            )
21986                        } else {
21987                            None
21988                        }
21989                    })
21990            });
21991
21992            cx.emit(EditorEvent::InputHandled {
21993                utf16_range_to_replace: range_to_replace,
21994                text: text.into(),
21995            });
21996
21997            if let Some(new_selected_ranges) = new_selected_ranges {
21998                this.change_selections(None, window, cx, |selections| {
21999                    selections.select_ranges(new_selected_ranges)
22000                });
22001                this.backspace(&Default::default(), window, cx);
22002            }
22003
22004            this.handle_input(text, window, cx);
22005        });
22006
22007        if let Some(transaction) = self.ime_transaction {
22008            self.buffer.update(cx, |buffer, cx| {
22009                buffer.group_until_transaction(transaction, cx);
22010            });
22011        }
22012
22013        self.unmark_text(window, cx);
22014    }
22015
22016    fn replace_and_mark_text_in_range(
22017        &mut self,
22018        range_utf16: Option<Range<usize>>,
22019        text: &str,
22020        new_selected_range_utf16: Option<Range<usize>>,
22021        window: &mut Window,
22022        cx: &mut Context<Self>,
22023    ) {
22024        if !self.input_enabled {
22025            return;
22026        }
22027
22028        let transaction = self.transact(window, cx, |this, window, cx| {
22029            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22030                let snapshot = this.buffer.read(cx).read(cx);
22031                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22032                    for marked_range in &mut marked_ranges {
22033                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22034                        marked_range.start.0 += relative_range_utf16.start;
22035                        marked_range.start =
22036                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22037                        marked_range.end =
22038                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22039                    }
22040                }
22041                Some(marked_ranges)
22042            } else if let Some(range_utf16) = range_utf16 {
22043                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22044                Some(this.selection_replacement_ranges(range_utf16, cx))
22045            } else {
22046                None
22047            };
22048
22049            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22050                let newest_selection_id = this.selections.newest_anchor().id;
22051                this.selections
22052                    .all::<OffsetUtf16>(cx)
22053                    .iter()
22054                    .zip(ranges_to_replace.iter())
22055                    .find_map(|(selection, range)| {
22056                        if selection.id == newest_selection_id {
22057                            Some(
22058                                (range.start.0 as isize - selection.head().0 as isize)
22059                                    ..(range.end.0 as isize - selection.head().0 as isize),
22060                            )
22061                        } else {
22062                            None
22063                        }
22064                    })
22065            });
22066
22067            cx.emit(EditorEvent::InputHandled {
22068                utf16_range_to_replace: range_to_replace,
22069                text: text.into(),
22070            });
22071
22072            if let Some(ranges) = ranges_to_replace {
22073                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22074            }
22075
22076            let marked_ranges = {
22077                let snapshot = this.buffer.read(cx).read(cx);
22078                this.selections
22079                    .disjoint_anchors()
22080                    .iter()
22081                    .map(|selection| {
22082                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22083                    })
22084                    .collect::<Vec<_>>()
22085            };
22086
22087            if text.is_empty() {
22088                this.unmark_text(window, cx);
22089            } else {
22090                this.highlight_text::<InputComposition>(
22091                    marked_ranges.clone(),
22092                    HighlightStyle {
22093                        underline: Some(UnderlineStyle {
22094                            thickness: px(1.),
22095                            color: None,
22096                            wavy: false,
22097                        }),
22098                        ..Default::default()
22099                    },
22100                    cx,
22101                );
22102            }
22103
22104            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22105            let use_autoclose = this.use_autoclose;
22106            let use_auto_surround = this.use_auto_surround;
22107            this.set_use_autoclose(false);
22108            this.set_use_auto_surround(false);
22109            this.handle_input(text, window, cx);
22110            this.set_use_autoclose(use_autoclose);
22111            this.set_use_auto_surround(use_auto_surround);
22112
22113            if let Some(new_selected_range) = new_selected_range_utf16 {
22114                let snapshot = this.buffer.read(cx).read(cx);
22115                let new_selected_ranges = marked_ranges
22116                    .into_iter()
22117                    .map(|marked_range| {
22118                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22119                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22120                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22121                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22122                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22123                    })
22124                    .collect::<Vec<_>>();
22125
22126                drop(snapshot);
22127                this.change_selections(None, window, cx, |selections| {
22128                    selections.select_ranges(new_selected_ranges)
22129                });
22130            }
22131        });
22132
22133        self.ime_transaction = self.ime_transaction.or(transaction);
22134        if let Some(transaction) = self.ime_transaction {
22135            self.buffer.update(cx, |buffer, cx| {
22136                buffer.group_until_transaction(transaction, cx);
22137            });
22138        }
22139
22140        if self.text_highlights::<InputComposition>(cx).is_none() {
22141            self.ime_transaction.take();
22142        }
22143    }
22144
22145    fn bounds_for_range(
22146        &mut self,
22147        range_utf16: Range<usize>,
22148        element_bounds: gpui::Bounds<Pixels>,
22149        window: &mut Window,
22150        cx: &mut Context<Self>,
22151    ) -> Option<gpui::Bounds<Pixels>> {
22152        let text_layout_details = self.text_layout_details(window);
22153        let gpui::Size {
22154            width: em_width,
22155            height: line_height,
22156        } = self.character_size(window);
22157
22158        let snapshot = self.snapshot(window, cx);
22159        let scroll_position = snapshot.scroll_position();
22160        let scroll_left = scroll_position.x * em_width;
22161
22162        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22163        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22164            + self.gutter_dimensions.width
22165            + self.gutter_dimensions.margin;
22166        let y = line_height * (start.row().as_f32() - scroll_position.y);
22167
22168        Some(Bounds {
22169            origin: element_bounds.origin + point(x, y),
22170            size: size(em_width, line_height),
22171        })
22172    }
22173
22174    fn character_index_for_point(
22175        &mut self,
22176        point: gpui::Point<Pixels>,
22177        _window: &mut Window,
22178        _cx: &mut Context<Self>,
22179    ) -> Option<usize> {
22180        let position_map = self.last_position_map.as_ref()?;
22181        if !position_map.text_hitbox.contains(&point) {
22182            return None;
22183        }
22184        let display_point = position_map.point_for_position(point).previous_valid;
22185        let anchor = position_map
22186            .snapshot
22187            .display_point_to_anchor(display_point, Bias::Left);
22188        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22189        Some(utf16_offset.0)
22190    }
22191}
22192
22193trait SelectionExt {
22194    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22195    fn spanned_rows(
22196        &self,
22197        include_end_if_at_line_start: bool,
22198        map: &DisplaySnapshot,
22199    ) -> Range<MultiBufferRow>;
22200}
22201
22202impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22203    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22204        let start = self
22205            .start
22206            .to_point(&map.buffer_snapshot)
22207            .to_display_point(map);
22208        let end = self
22209            .end
22210            .to_point(&map.buffer_snapshot)
22211            .to_display_point(map);
22212        if self.reversed {
22213            end..start
22214        } else {
22215            start..end
22216        }
22217    }
22218
22219    fn spanned_rows(
22220        &self,
22221        include_end_if_at_line_start: bool,
22222        map: &DisplaySnapshot,
22223    ) -> Range<MultiBufferRow> {
22224        let start = self.start.to_point(&map.buffer_snapshot);
22225        let mut end = self.end.to_point(&map.buffer_snapshot);
22226        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22227            end.row -= 1;
22228        }
22229
22230        let buffer_start = map.prev_line_boundary(start).0;
22231        let buffer_end = map.next_line_boundary(end).0;
22232        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22233    }
22234}
22235
22236impl<T: InvalidationRegion> InvalidationStack<T> {
22237    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22238    where
22239        S: Clone + ToOffset,
22240    {
22241        while let Some(region) = self.last() {
22242            let all_selections_inside_invalidation_ranges =
22243                if selections.len() == region.ranges().len() {
22244                    selections
22245                        .iter()
22246                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22247                        .all(|(selection, invalidation_range)| {
22248                            let head = selection.head().to_offset(buffer);
22249                            invalidation_range.start <= head && invalidation_range.end >= head
22250                        })
22251                } else {
22252                    false
22253                };
22254
22255            if all_selections_inside_invalidation_ranges {
22256                break;
22257            } else {
22258                self.pop();
22259            }
22260        }
22261    }
22262}
22263
22264impl<T> Default for InvalidationStack<T> {
22265    fn default() -> Self {
22266        Self(Default::default())
22267    }
22268}
22269
22270impl<T> Deref for InvalidationStack<T> {
22271    type Target = Vec<T>;
22272
22273    fn deref(&self) -> &Self::Target {
22274        &self.0
22275    }
22276}
22277
22278impl<T> DerefMut for InvalidationStack<T> {
22279    fn deref_mut(&mut self) -> &mut Self::Target {
22280        &mut self.0
22281    }
22282}
22283
22284impl InvalidationRegion for SnippetState {
22285    fn ranges(&self) -> &[Range<Anchor>] {
22286        &self.ranges[self.active_index]
22287    }
22288}
22289
22290fn inline_completion_edit_text(
22291    current_snapshot: &BufferSnapshot,
22292    edits: &[(Range<Anchor>, String)],
22293    edit_preview: &EditPreview,
22294    include_deletions: bool,
22295    cx: &App,
22296) -> HighlightedText {
22297    let edits = edits
22298        .iter()
22299        .map(|(anchor, text)| {
22300            (
22301                anchor.start.text_anchor..anchor.end.text_anchor,
22302                text.clone(),
22303            )
22304        })
22305        .collect::<Vec<_>>();
22306
22307    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22308}
22309
22310pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22311    match severity {
22312        lsp::DiagnosticSeverity::ERROR => colors.error,
22313        lsp::DiagnosticSeverity::WARNING => colors.warning,
22314        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22315        lsp::DiagnosticSeverity::HINT => colors.info,
22316        _ => colors.ignored,
22317    }
22318}
22319
22320pub fn styled_runs_for_code_label<'a>(
22321    label: &'a CodeLabel,
22322    syntax_theme: &'a theme::SyntaxTheme,
22323) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22324    let fade_out = HighlightStyle {
22325        fade_out: Some(0.35),
22326        ..Default::default()
22327    };
22328
22329    let mut prev_end = label.filter_range.end;
22330    label
22331        .runs
22332        .iter()
22333        .enumerate()
22334        .flat_map(move |(ix, (range, highlight_id))| {
22335            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22336                style
22337            } else {
22338                return Default::default();
22339            };
22340            let mut muted_style = style;
22341            muted_style.highlight(fade_out);
22342
22343            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22344            if range.start >= label.filter_range.end {
22345                if range.start > prev_end {
22346                    runs.push((prev_end..range.start, fade_out));
22347                }
22348                runs.push((range.clone(), muted_style));
22349            } else if range.end <= label.filter_range.end {
22350                runs.push((range.clone(), style));
22351            } else {
22352                runs.push((range.start..label.filter_range.end, style));
22353                runs.push((label.filter_range.end..range.end, muted_style));
22354            }
22355            prev_end = cmp::max(prev_end, range.end);
22356
22357            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22358                runs.push((prev_end..label.text.len(), fade_out));
22359            }
22360
22361            runs
22362        })
22363}
22364
22365pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22366    let mut prev_index = 0;
22367    let mut prev_codepoint: Option<char> = None;
22368    text.char_indices()
22369        .chain([(text.len(), '\0')])
22370        .filter_map(move |(index, codepoint)| {
22371            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22372            let is_boundary = index == text.len()
22373                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22374                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22375            if is_boundary {
22376                let chunk = &text[prev_index..index];
22377                prev_index = index;
22378                Some(chunk)
22379            } else {
22380                None
22381            }
22382        })
22383}
22384
22385pub trait RangeToAnchorExt: Sized {
22386    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22387
22388    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22389        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22390        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22391    }
22392}
22393
22394impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22395    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22396        let start_offset = self.start.to_offset(snapshot);
22397        let end_offset = self.end.to_offset(snapshot);
22398        if start_offset == end_offset {
22399            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22400        } else {
22401            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22402        }
22403    }
22404}
22405
22406pub trait RowExt {
22407    fn as_f32(&self) -> f32;
22408
22409    fn next_row(&self) -> Self;
22410
22411    fn previous_row(&self) -> Self;
22412
22413    fn minus(&self, other: Self) -> u32;
22414}
22415
22416impl RowExt for DisplayRow {
22417    fn as_f32(&self) -> f32 {
22418        self.0 as f32
22419    }
22420
22421    fn next_row(&self) -> Self {
22422        Self(self.0 + 1)
22423    }
22424
22425    fn previous_row(&self) -> Self {
22426        Self(self.0.saturating_sub(1))
22427    }
22428
22429    fn minus(&self, other: Self) -> u32 {
22430        self.0 - other.0
22431    }
22432}
22433
22434impl RowExt for MultiBufferRow {
22435    fn as_f32(&self) -> f32 {
22436        self.0 as f32
22437    }
22438
22439    fn next_row(&self) -> Self {
22440        Self(self.0 + 1)
22441    }
22442
22443    fn previous_row(&self) -> Self {
22444        Self(self.0.saturating_sub(1))
22445    }
22446
22447    fn minus(&self, other: Self) -> u32 {
22448        self.0 - other.0
22449    }
22450}
22451
22452trait RowRangeExt {
22453    type Row;
22454
22455    fn len(&self) -> usize;
22456
22457    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22458}
22459
22460impl RowRangeExt for Range<MultiBufferRow> {
22461    type Row = MultiBufferRow;
22462
22463    fn len(&self) -> usize {
22464        (self.end.0 - self.start.0) as usize
22465    }
22466
22467    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22468        (self.start.0..self.end.0).map(MultiBufferRow)
22469    }
22470}
22471
22472impl RowRangeExt for Range<DisplayRow> {
22473    type Row = DisplayRow;
22474
22475    fn len(&self) -> usize {
22476        (self.end.0 - self.start.0) as usize
22477    }
22478
22479    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22480        (self.start.0..self.end.0).map(DisplayRow)
22481    }
22482}
22483
22484/// If select range has more than one line, we
22485/// just point the cursor to range.start.
22486fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22487    if range.start.row == range.end.row {
22488        range
22489    } else {
22490        range.start..range.start
22491    }
22492}
22493pub struct KillRing(ClipboardItem);
22494impl Global for KillRing {}
22495
22496const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22497
22498enum BreakpointPromptEditAction {
22499    Log,
22500    Condition,
22501    HitCondition,
22502}
22503
22504struct BreakpointPromptEditor {
22505    pub(crate) prompt: Entity<Editor>,
22506    editor: WeakEntity<Editor>,
22507    breakpoint_anchor: Anchor,
22508    breakpoint: Breakpoint,
22509    edit_action: BreakpointPromptEditAction,
22510    block_ids: HashSet<CustomBlockId>,
22511    editor_margins: Arc<Mutex<EditorMargins>>,
22512    _subscriptions: Vec<Subscription>,
22513}
22514
22515impl BreakpointPromptEditor {
22516    const MAX_LINES: u8 = 4;
22517
22518    fn new(
22519        editor: WeakEntity<Editor>,
22520        breakpoint_anchor: Anchor,
22521        breakpoint: Breakpoint,
22522        edit_action: BreakpointPromptEditAction,
22523        window: &mut Window,
22524        cx: &mut Context<Self>,
22525    ) -> Self {
22526        let base_text = match edit_action {
22527            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22528            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22529            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22530        }
22531        .map(|msg| msg.to_string())
22532        .unwrap_or_default();
22533
22534        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22535        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22536
22537        let prompt = cx.new(|cx| {
22538            let mut prompt = Editor::new(
22539                EditorMode::AutoHeight {
22540                    max_lines: Self::MAX_LINES as usize,
22541                },
22542                buffer,
22543                None,
22544                window,
22545                cx,
22546            );
22547            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22548            prompt.set_show_cursor_when_unfocused(false, cx);
22549            prompt.set_placeholder_text(
22550                match edit_action {
22551                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22552                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22553                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22554                },
22555                cx,
22556            );
22557
22558            prompt
22559        });
22560
22561        Self {
22562            prompt,
22563            editor,
22564            breakpoint_anchor,
22565            breakpoint,
22566            edit_action,
22567            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22568            block_ids: Default::default(),
22569            _subscriptions: vec![],
22570        }
22571    }
22572
22573    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22574        self.block_ids.extend(block_ids)
22575    }
22576
22577    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22578        if let Some(editor) = self.editor.upgrade() {
22579            let message = self
22580                .prompt
22581                .read(cx)
22582                .buffer
22583                .read(cx)
22584                .as_singleton()
22585                .expect("A multi buffer in breakpoint prompt isn't possible")
22586                .read(cx)
22587                .as_rope()
22588                .to_string();
22589
22590            editor.update(cx, |editor, cx| {
22591                editor.edit_breakpoint_at_anchor(
22592                    self.breakpoint_anchor,
22593                    self.breakpoint.clone(),
22594                    match self.edit_action {
22595                        BreakpointPromptEditAction::Log => {
22596                            BreakpointEditAction::EditLogMessage(message.into())
22597                        }
22598                        BreakpointPromptEditAction::Condition => {
22599                            BreakpointEditAction::EditCondition(message.into())
22600                        }
22601                        BreakpointPromptEditAction::HitCondition => {
22602                            BreakpointEditAction::EditHitCondition(message.into())
22603                        }
22604                    },
22605                    cx,
22606                );
22607
22608                editor.remove_blocks(self.block_ids.clone(), None, cx);
22609                cx.focus_self(window);
22610            });
22611        }
22612    }
22613
22614    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22615        self.editor
22616            .update(cx, |editor, cx| {
22617                editor.remove_blocks(self.block_ids.clone(), None, cx);
22618                window.focus(&editor.focus_handle);
22619            })
22620            .log_err();
22621    }
22622
22623    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22624        let settings = ThemeSettings::get_global(cx);
22625        let text_style = TextStyle {
22626            color: if self.prompt.read(cx).read_only(cx) {
22627                cx.theme().colors().text_disabled
22628            } else {
22629                cx.theme().colors().text
22630            },
22631            font_family: settings.buffer_font.family.clone(),
22632            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22633            font_size: settings.buffer_font_size(cx).into(),
22634            font_weight: settings.buffer_font.weight,
22635            line_height: relative(settings.buffer_line_height.value()),
22636            ..Default::default()
22637        };
22638        EditorElement::new(
22639            &self.prompt,
22640            EditorStyle {
22641                background: cx.theme().colors().editor_background,
22642                local_player: cx.theme().players().local(),
22643                text: text_style,
22644                ..Default::default()
22645            },
22646        )
22647    }
22648}
22649
22650impl Render for BreakpointPromptEditor {
22651    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22652        let editor_margins = *self.editor_margins.lock();
22653        let gutter_dimensions = editor_margins.gutter;
22654        h_flex()
22655            .key_context("Editor")
22656            .bg(cx.theme().colors().editor_background)
22657            .border_y_1()
22658            .border_color(cx.theme().status().info_border)
22659            .size_full()
22660            .py(window.line_height() / 2.5)
22661            .on_action(cx.listener(Self::confirm))
22662            .on_action(cx.listener(Self::cancel))
22663            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22664            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22665    }
22666}
22667
22668impl Focusable for BreakpointPromptEditor {
22669    fn focus_handle(&self, cx: &App) -> FocusHandle {
22670        self.prompt.focus_handle(cx)
22671    }
22672}
22673
22674fn all_edits_insertions_or_deletions(
22675    edits: &Vec<(Range<Anchor>, String)>,
22676    snapshot: &MultiBufferSnapshot,
22677) -> bool {
22678    let mut all_insertions = true;
22679    let mut all_deletions = true;
22680
22681    for (range, new_text) in edits.iter() {
22682        let range_is_empty = range.to_offset(&snapshot).is_empty();
22683        let text_is_empty = new_text.is_empty();
22684
22685        if range_is_empty != text_is_empty {
22686            if range_is_empty {
22687                all_deletions = false;
22688            } else {
22689                all_insertions = false;
22690            }
22691        } else {
22692            return false;
22693        }
22694
22695        if !all_insertions && !all_deletions {
22696            return false;
22697        }
22698    }
22699    all_insertions || all_deletions
22700}
22701
22702struct MissingEditPredictionKeybindingTooltip;
22703
22704impl Render for MissingEditPredictionKeybindingTooltip {
22705    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22706        ui::tooltip_container(window, cx, |container, _, cx| {
22707            container
22708                .flex_shrink_0()
22709                .max_w_80()
22710                .min_h(rems_from_px(124.))
22711                .justify_between()
22712                .child(
22713                    v_flex()
22714                        .flex_1()
22715                        .text_ui_sm(cx)
22716                        .child(Label::new("Conflict with Accept Keybinding"))
22717                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22718                )
22719                .child(
22720                    h_flex()
22721                        .pb_1()
22722                        .gap_1()
22723                        .items_end()
22724                        .w_full()
22725                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22726                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22727                        }))
22728                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22729                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22730                        })),
22731                )
22732        })
22733    }
22734}
22735
22736#[derive(Debug, Clone, Copy, PartialEq)]
22737pub struct LineHighlight {
22738    pub background: Background,
22739    pub border: Option<gpui::Hsla>,
22740    pub include_gutter: bool,
22741    pub type_id: Option<TypeId>,
22742}
22743
22744fn render_diff_hunk_controls(
22745    row: u32,
22746    status: &DiffHunkStatus,
22747    hunk_range: Range<Anchor>,
22748    is_created_file: bool,
22749    line_height: Pixels,
22750    editor: &Entity<Editor>,
22751    _window: &mut Window,
22752    cx: &mut App,
22753) -> AnyElement {
22754    h_flex()
22755        .h(line_height)
22756        .mr_1()
22757        .gap_1()
22758        .px_0p5()
22759        .pb_1()
22760        .border_x_1()
22761        .border_b_1()
22762        .border_color(cx.theme().colors().border_variant)
22763        .rounded_b_lg()
22764        .bg(cx.theme().colors().editor_background)
22765        .gap_1()
22766        .block_mouse_except_scroll()
22767        .shadow_md()
22768        .child(if status.has_secondary_hunk() {
22769            Button::new(("stage", row as u64), "Stage")
22770                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22771                .tooltip({
22772                    let focus_handle = editor.focus_handle(cx);
22773                    move |window, cx| {
22774                        Tooltip::for_action_in(
22775                            "Stage Hunk",
22776                            &::git::ToggleStaged,
22777                            &focus_handle,
22778                            window,
22779                            cx,
22780                        )
22781                    }
22782                })
22783                .on_click({
22784                    let editor = editor.clone();
22785                    move |_event, _window, cx| {
22786                        editor.update(cx, |editor, cx| {
22787                            editor.stage_or_unstage_diff_hunks(
22788                                true,
22789                                vec![hunk_range.start..hunk_range.start],
22790                                cx,
22791                            );
22792                        });
22793                    }
22794                })
22795        } else {
22796            Button::new(("unstage", row as u64), "Unstage")
22797                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22798                .tooltip({
22799                    let focus_handle = editor.focus_handle(cx);
22800                    move |window, cx| {
22801                        Tooltip::for_action_in(
22802                            "Unstage Hunk",
22803                            &::git::ToggleStaged,
22804                            &focus_handle,
22805                            window,
22806                            cx,
22807                        )
22808                    }
22809                })
22810                .on_click({
22811                    let editor = editor.clone();
22812                    move |_event, _window, cx| {
22813                        editor.update(cx, |editor, cx| {
22814                            editor.stage_or_unstage_diff_hunks(
22815                                false,
22816                                vec![hunk_range.start..hunk_range.start],
22817                                cx,
22818                            );
22819                        });
22820                    }
22821                })
22822        })
22823        .child(
22824            Button::new(("restore", row as u64), "Restore")
22825                .tooltip({
22826                    let focus_handle = editor.focus_handle(cx);
22827                    move |window, cx| {
22828                        Tooltip::for_action_in(
22829                            "Restore Hunk",
22830                            &::git::Restore,
22831                            &focus_handle,
22832                            window,
22833                            cx,
22834                        )
22835                    }
22836                })
22837                .on_click({
22838                    let editor = editor.clone();
22839                    move |_event, window, cx| {
22840                        editor.update(cx, |editor, cx| {
22841                            let snapshot = editor.snapshot(window, cx);
22842                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22843                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22844                        });
22845                    }
22846                })
22847                .disabled(is_created_file),
22848        )
22849        .when(
22850            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22851            |el| {
22852                el.child(
22853                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22854                        .shape(IconButtonShape::Square)
22855                        .icon_size(IconSize::Small)
22856                        // .disabled(!has_multiple_hunks)
22857                        .tooltip({
22858                            let focus_handle = editor.focus_handle(cx);
22859                            move |window, cx| {
22860                                Tooltip::for_action_in(
22861                                    "Next Hunk",
22862                                    &GoToHunk,
22863                                    &focus_handle,
22864                                    window,
22865                                    cx,
22866                                )
22867                            }
22868                        })
22869                        .on_click({
22870                            let editor = editor.clone();
22871                            move |_event, window, cx| {
22872                                editor.update(cx, |editor, cx| {
22873                                    let snapshot = editor.snapshot(window, cx);
22874                                    let position =
22875                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22876                                    editor.go_to_hunk_before_or_after_position(
22877                                        &snapshot,
22878                                        position,
22879                                        Direction::Next,
22880                                        window,
22881                                        cx,
22882                                    );
22883                                    editor.expand_selected_diff_hunks(cx);
22884                                });
22885                            }
22886                        }),
22887                )
22888                .child(
22889                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22890                        .shape(IconButtonShape::Square)
22891                        .icon_size(IconSize::Small)
22892                        // .disabled(!has_multiple_hunks)
22893                        .tooltip({
22894                            let focus_handle = editor.focus_handle(cx);
22895                            move |window, cx| {
22896                                Tooltip::for_action_in(
22897                                    "Previous Hunk",
22898                                    &GoToPreviousHunk,
22899                                    &focus_handle,
22900                                    window,
22901                                    cx,
22902                                )
22903                            }
22904                        })
22905                        .on_click({
22906                            let editor = editor.clone();
22907                            move |_event, window, cx| {
22908                                editor.update(cx, |editor, cx| {
22909                                    let snapshot = editor.snapshot(window, cx);
22910                                    let point =
22911                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22912                                    editor.go_to_hunk_before_or_after_position(
22913                                        &snapshot,
22914                                        point,
22915                                        Direction::Prev,
22916                                        window,
22917                                        cx,
22918                                    );
22919                                    editor.expand_selected_diff_hunks(cx);
22920                                });
22921                            }
22922                        }),
22923                )
22924            },
22925        )
22926        .into_any_element()
22927}