editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296pub enum PendingInput {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908enum SelectionDragState {
  909    /// State when no drag related activity is detected.
  910    None,
  911    /// State when the mouse is down on a selection that is about to be dragged.
  912    ReadyToDrag {
  913        selection: Selection<Anchor>,
  914        click_position: gpui::Point<Pixels>,
  915    },
  916    /// State when the mouse is dragging the selection in the editor.
  917    Dragging {
  918        selection: Selection<Anchor>,
  919        drop_cursor: Selection<Anchor>,
  920        hide_drop_cursor: bool,
  921    },
  922}
  923
  924/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  925/// a breakpoint on them.
  926#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  927struct PhantomBreakpointIndicator {
  928    display_row: DisplayRow,
  929    /// There's a small debounce between hovering over the line and showing the indicator.
  930    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  931    is_active: bool,
  932    collides_with_existing_breakpoint: bool,
  933}
  934
  935/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  936///
  937/// See the [module level documentation](self) for more information.
  938pub struct Editor {
  939    focus_handle: FocusHandle,
  940    last_focused_descendant: Option<WeakFocusHandle>,
  941    /// The text buffer being edited
  942    buffer: Entity<MultiBuffer>,
  943    /// Map of how text in the buffer should be displayed.
  944    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  945    pub display_map: Entity<DisplayMap>,
  946    pub selections: SelectionsCollection,
  947    pub scroll_manager: ScrollManager,
  948    /// When inline assist editors are linked, they all render cursors because
  949    /// typing enters text into each of them, even the ones that aren't focused.
  950    pub(crate) show_cursor_when_unfocused: bool,
  951    columnar_selection_tail: Option<Anchor>,
  952    columnar_display_point: Option<DisplayPoint>,
  953    add_selections_state: Option<AddSelectionsState>,
  954    select_next_state: Option<SelectNextState>,
  955    select_prev_state: Option<SelectNextState>,
  956    selection_history: SelectionHistory,
  957    defer_selection_effects: bool,
  958    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  959    autoclose_regions: Vec<AutocloseRegion>,
  960    snippet_stack: InvalidationStack<SnippetState>,
  961    select_syntax_node_history: SelectSyntaxNodeHistory,
  962    ime_transaction: Option<TransactionId>,
  963    pub diagnostics_max_severity: DiagnosticSeverity,
  964    active_diagnostics: ActiveDiagnostic,
  965    show_inline_diagnostics: bool,
  966    inline_diagnostics_update: Task<()>,
  967    inline_diagnostics_enabled: bool,
  968    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  969    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  970    hard_wrap: Option<usize>,
  971
  972    // TODO: make this a access method
  973    pub project: Option<Entity<Project>>,
  974    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  975    completion_provider: Option<Rc<dyn CompletionProvider>>,
  976    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  977    blink_manager: Entity<BlinkManager>,
  978    show_cursor_names: bool,
  979    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  980    pub show_local_selections: bool,
  981    mode: EditorMode,
  982    show_breadcrumbs: bool,
  983    show_gutter: bool,
  984    show_scrollbars: ScrollbarAxes,
  985    minimap_visibility: MinimapVisibility,
  986    offset_content: bool,
  987    disable_expand_excerpt_buttons: bool,
  988    show_line_numbers: Option<bool>,
  989    use_relative_line_numbers: Option<bool>,
  990    show_git_diff_gutter: Option<bool>,
  991    show_code_actions: Option<bool>,
  992    show_runnables: Option<bool>,
  993    show_breakpoints: Option<bool>,
  994    show_wrap_guides: Option<bool>,
  995    show_indent_guides: Option<bool>,
  996    placeholder_text: Option<Arc<str>>,
  997    highlight_order: usize,
  998    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  999    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1000    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1001    scrollbar_marker_state: ScrollbarMarkerState,
 1002    active_indent_guides_state: ActiveIndentGuidesState,
 1003    nav_history: Option<ItemNavHistory>,
 1004    context_menu: RefCell<Option<CodeContextMenu>>,
 1005    context_menu_options: Option<ContextMenuOptions>,
 1006    mouse_context_menu: Option<MouseContextMenu>,
 1007    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1008    inline_blame_popover: Option<InlineBlamePopover>,
 1009    signature_help_state: SignatureHelpState,
 1010    auto_signature_help: Option<bool>,
 1011    find_all_references_task_sources: Vec<Anchor>,
 1012    next_completion_id: CompletionId,
 1013    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1014    code_actions_task: Option<Task<Result<()>>>,
 1015    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1016    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    document_highlights_task: Option<Task<()>>,
 1018    linked_editing_range_task: Option<Task<Option<()>>>,
 1019    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1020    pending_rename: Option<RenameState>,
 1021    searchable: bool,
 1022    cursor_shape: CursorShape,
 1023    current_line_highlight: Option<CurrentLineHighlight>,
 1024    collapse_matches: bool,
 1025    autoindent_mode: Option<AutoindentMode>,
 1026    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1027    input_enabled: bool,
 1028    use_modal_editing: bool,
 1029    read_only: bool,
 1030    leader_id: Option<CollaboratorId>,
 1031    remote_id: Option<ViewId>,
 1032    pub hover_state: HoverState,
 1033    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1034    gutter_hovered: bool,
 1035    hovered_link_state: Option<HoveredLinkState>,
 1036    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1037    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1038    active_inline_completion: Option<InlineCompletionState>,
 1039    /// Used to prevent flickering as the user types while the menu is open
 1040    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1041    edit_prediction_settings: EditPredictionSettings,
 1042    inline_completions_hidden_for_vim_mode: bool,
 1043    show_inline_completions_override: Option<bool>,
 1044    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1045    edit_prediction_preview: EditPredictionPreview,
 1046    edit_prediction_indent_conflict: bool,
 1047    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1048    inlay_hint_cache: InlayHintCache,
 1049    next_inlay_id: usize,
 1050    _subscriptions: Vec<Subscription>,
 1051    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1052    gutter_dimensions: GutterDimensions,
 1053    style: Option<EditorStyle>,
 1054    text_style_refinement: Option<TextStyleRefinement>,
 1055    next_editor_action_id: EditorActionId,
 1056    editor_actions: Rc<
 1057        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1058    >,
 1059    use_autoclose: bool,
 1060    use_auto_surround: bool,
 1061    auto_replace_emoji_shortcode: bool,
 1062    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1063    show_git_blame_gutter: bool,
 1064    show_git_blame_inline: bool,
 1065    show_git_blame_inline_delay_task: Option<Task<()>>,
 1066    git_blame_inline_enabled: bool,
 1067    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1068    serialize_dirty_buffers: bool,
 1069    show_selection_menu: Option<bool>,
 1070    blame: Option<Entity<GitBlame>>,
 1071    blame_subscription: Option<Subscription>,
 1072    custom_context_menu: Option<
 1073        Box<
 1074            dyn 'static
 1075                + Fn(
 1076                    &mut Self,
 1077                    DisplayPoint,
 1078                    &mut Window,
 1079                    &mut Context<Self>,
 1080                ) -> Option<Entity<ui::ContextMenu>>,
 1081        >,
 1082    >,
 1083    last_bounds: Option<Bounds<Pixels>>,
 1084    last_position_map: Option<Rc<PositionMap>>,
 1085    expect_bounds_change: Option<Bounds<Pixels>>,
 1086    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1087    tasks_update_task: Option<Task<()>>,
 1088    breakpoint_store: Option<Entity<BreakpointStore>>,
 1089    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1090    pull_diagnostics_task: Task<()>,
 1091    in_project_search: bool,
 1092    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1093    breadcrumb_header: Option<String>,
 1094    focused_block: Option<FocusedBlock>,
 1095    next_scroll_position: NextScrollCursorCenterTopBottom,
 1096    addons: HashMap<TypeId, Box<dyn Addon>>,
 1097    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1098    load_diff_task: Option<Shared<Task<()>>>,
 1099    /// Whether we are temporarily displaying a diff other than git's
 1100    temporary_diff_override: bool,
 1101    selection_mark_mode: bool,
 1102    toggle_fold_multiple_buffers: Task<()>,
 1103    _scroll_cursor_center_top_bottom_task: Task<()>,
 1104    serialize_selections: Task<()>,
 1105    serialize_folds: Task<()>,
 1106    mouse_cursor_hidden: bool,
 1107    minimap: Option<Entity<Self>>,
 1108    hide_mouse_mode: HideMouseMode,
 1109    pub change_list: ChangeList,
 1110    inline_value_cache: InlineValueCache,
 1111    selection_drag_state: SelectionDragState,
 1112    drag_and_drop_selection_enabled: bool,
 1113}
 1114
 1115#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1116enum NextScrollCursorCenterTopBottom {
 1117    #[default]
 1118    Center,
 1119    Top,
 1120    Bottom,
 1121}
 1122
 1123impl NextScrollCursorCenterTopBottom {
 1124    fn next(&self) -> Self {
 1125        match self {
 1126            Self::Center => Self::Top,
 1127            Self::Top => Self::Bottom,
 1128            Self::Bottom => Self::Center,
 1129        }
 1130    }
 1131}
 1132
 1133#[derive(Clone)]
 1134pub struct EditorSnapshot {
 1135    pub mode: EditorMode,
 1136    show_gutter: bool,
 1137    show_line_numbers: Option<bool>,
 1138    show_git_diff_gutter: Option<bool>,
 1139    show_code_actions: Option<bool>,
 1140    show_runnables: Option<bool>,
 1141    show_breakpoints: Option<bool>,
 1142    git_blame_gutter_max_author_length: Option<usize>,
 1143    pub display_snapshot: DisplaySnapshot,
 1144    pub placeholder_text: Option<Arc<str>>,
 1145    is_focused: bool,
 1146    scroll_anchor: ScrollAnchor,
 1147    ongoing_scroll: OngoingScroll,
 1148    current_line_highlight: CurrentLineHighlight,
 1149    gutter_hovered: bool,
 1150}
 1151
 1152#[derive(Default, Debug, Clone, Copy)]
 1153pub struct GutterDimensions {
 1154    pub left_padding: Pixels,
 1155    pub right_padding: Pixels,
 1156    pub width: Pixels,
 1157    pub margin: Pixels,
 1158    pub git_blame_entries_width: Option<Pixels>,
 1159}
 1160
 1161impl GutterDimensions {
 1162    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1163        Self {
 1164            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1165            ..Default::default()
 1166        }
 1167    }
 1168
 1169    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1170        -cx.text_system().descent(font_id, font_size)
 1171    }
 1172    /// The full width of the space taken up by the gutter.
 1173    pub fn full_width(&self) -> Pixels {
 1174        self.margin + self.width
 1175    }
 1176
 1177    /// The width of the space reserved for the fold indicators,
 1178    /// use alongside 'justify_end' and `gutter_width` to
 1179    /// right align content with the line numbers
 1180    pub fn fold_area_width(&self) -> Pixels {
 1181        self.margin + self.right_padding
 1182    }
 1183}
 1184
 1185#[derive(Debug)]
 1186pub struct RemoteSelection {
 1187    pub replica_id: ReplicaId,
 1188    pub selection: Selection<Anchor>,
 1189    pub cursor_shape: CursorShape,
 1190    pub collaborator_id: CollaboratorId,
 1191    pub line_mode: bool,
 1192    pub user_name: Option<SharedString>,
 1193    pub color: PlayerColor,
 1194}
 1195
 1196#[derive(Clone, Debug)]
 1197struct SelectionHistoryEntry {
 1198    selections: Arc<[Selection<Anchor>]>,
 1199    select_next_state: Option<SelectNextState>,
 1200    select_prev_state: Option<SelectNextState>,
 1201    add_selections_state: Option<AddSelectionsState>,
 1202}
 1203
 1204#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1205enum SelectionHistoryMode {
 1206    Normal,
 1207    Undoing,
 1208    Redoing,
 1209    Skipping,
 1210}
 1211
 1212#[derive(Clone, PartialEq, Eq, Hash)]
 1213struct HoveredCursor {
 1214    replica_id: u16,
 1215    selection_id: usize,
 1216}
 1217
 1218impl Default for SelectionHistoryMode {
 1219    fn default() -> Self {
 1220        Self::Normal
 1221    }
 1222}
 1223
 1224struct DeferredSelectionEffectsState {
 1225    changed: bool,
 1226    should_update_completions: bool,
 1227    autoscroll: Option<Autoscroll>,
 1228    old_cursor_position: Anchor,
 1229    history_entry: SelectionHistoryEntry,
 1230}
 1231
 1232#[derive(Default)]
 1233struct SelectionHistory {
 1234    #[allow(clippy::type_complexity)]
 1235    selections_by_transaction:
 1236        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1237    mode: SelectionHistoryMode,
 1238    undo_stack: VecDeque<SelectionHistoryEntry>,
 1239    redo_stack: VecDeque<SelectionHistoryEntry>,
 1240}
 1241
 1242impl SelectionHistory {
 1243    #[track_caller]
 1244    fn insert_transaction(
 1245        &mut self,
 1246        transaction_id: TransactionId,
 1247        selections: Arc<[Selection<Anchor>]>,
 1248    ) {
 1249        if selections.is_empty() {
 1250            log::error!(
 1251                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1252                std::panic::Location::caller()
 1253            );
 1254            return;
 1255        }
 1256        self.selections_by_transaction
 1257            .insert(transaction_id, (selections, None));
 1258    }
 1259
 1260    #[allow(clippy::type_complexity)]
 1261    fn transaction(
 1262        &self,
 1263        transaction_id: TransactionId,
 1264    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1265        self.selections_by_transaction.get(&transaction_id)
 1266    }
 1267
 1268    #[allow(clippy::type_complexity)]
 1269    fn transaction_mut(
 1270        &mut self,
 1271        transaction_id: TransactionId,
 1272    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1273        self.selections_by_transaction.get_mut(&transaction_id)
 1274    }
 1275
 1276    fn push(&mut self, entry: SelectionHistoryEntry) {
 1277        if !entry.selections.is_empty() {
 1278            match self.mode {
 1279                SelectionHistoryMode::Normal => {
 1280                    self.push_undo(entry);
 1281                    self.redo_stack.clear();
 1282                }
 1283                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1284                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1285                SelectionHistoryMode::Skipping => {}
 1286            }
 1287        }
 1288    }
 1289
 1290    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1291        if self
 1292            .undo_stack
 1293            .back()
 1294            .map_or(true, |e| e.selections != entry.selections)
 1295        {
 1296            self.undo_stack.push_back(entry);
 1297            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1298                self.undo_stack.pop_front();
 1299            }
 1300        }
 1301    }
 1302
 1303    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1304        if self
 1305            .redo_stack
 1306            .back()
 1307            .map_or(true, |e| e.selections != entry.selections)
 1308        {
 1309            self.redo_stack.push_back(entry);
 1310            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1311                self.redo_stack.pop_front();
 1312            }
 1313        }
 1314    }
 1315}
 1316
 1317#[derive(Clone, Copy)]
 1318pub struct RowHighlightOptions {
 1319    pub autoscroll: bool,
 1320    pub include_gutter: bool,
 1321}
 1322
 1323impl Default for RowHighlightOptions {
 1324    fn default() -> Self {
 1325        Self {
 1326            autoscroll: Default::default(),
 1327            include_gutter: true,
 1328        }
 1329    }
 1330}
 1331
 1332struct RowHighlight {
 1333    index: usize,
 1334    range: Range<Anchor>,
 1335    color: Hsla,
 1336    options: RowHighlightOptions,
 1337    type_id: TypeId,
 1338}
 1339
 1340#[derive(Clone, Debug)]
 1341struct AddSelectionsState {
 1342    groups: Vec<AddSelectionsGroup>,
 1343}
 1344
 1345#[derive(Clone, Debug)]
 1346struct AddSelectionsGroup {
 1347    above: bool,
 1348    stack: Vec<usize>,
 1349}
 1350
 1351#[derive(Clone)]
 1352struct SelectNextState {
 1353    query: AhoCorasick,
 1354    wordwise: bool,
 1355    done: bool,
 1356}
 1357
 1358impl std::fmt::Debug for SelectNextState {
 1359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1360        f.debug_struct(std::any::type_name::<Self>())
 1361            .field("wordwise", &self.wordwise)
 1362            .field("done", &self.done)
 1363            .finish()
 1364    }
 1365}
 1366
 1367#[derive(Debug)]
 1368struct AutocloseRegion {
 1369    selection_id: usize,
 1370    range: Range<Anchor>,
 1371    pair: BracketPair,
 1372}
 1373
 1374#[derive(Debug)]
 1375struct SnippetState {
 1376    ranges: Vec<Vec<Range<Anchor>>>,
 1377    active_index: usize,
 1378    choices: Vec<Option<Vec<String>>>,
 1379}
 1380
 1381#[doc(hidden)]
 1382pub struct RenameState {
 1383    pub range: Range<Anchor>,
 1384    pub old_name: Arc<str>,
 1385    pub editor: Entity<Editor>,
 1386    block_id: CustomBlockId,
 1387}
 1388
 1389struct InvalidationStack<T>(Vec<T>);
 1390
 1391struct RegisteredInlineCompletionProvider {
 1392    provider: Arc<dyn InlineCompletionProviderHandle>,
 1393    _subscription: Subscription,
 1394}
 1395
 1396#[derive(Debug, PartialEq, Eq)]
 1397pub struct ActiveDiagnosticGroup {
 1398    pub active_range: Range<Anchor>,
 1399    pub active_message: String,
 1400    pub group_id: usize,
 1401    pub blocks: HashSet<CustomBlockId>,
 1402}
 1403
 1404#[derive(Debug, PartialEq, Eq)]
 1405
 1406pub(crate) enum ActiveDiagnostic {
 1407    None,
 1408    All,
 1409    Group(ActiveDiagnosticGroup),
 1410}
 1411
 1412#[derive(Serialize, Deserialize, Clone, Debug)]
 1413pub struct ClipboardSelection {
 1414    /// The number of bytes in this selection.
 1415    pub len: usize,
 1416    /// Whether this was a full-line selection.
 1417    pub is_entire_line: bool,
 1418    /// The indentation of the first line when this content was originally copied.
 1419    pub first_line_indent: u32,
 1420}
 1421
 1422// selections, scroll behavior, was newest selection reversed
 1423type SelectSyntaxNodeHistoryState = (
 1424    Box<[Selection<usize>]>,
 1425    SelectSyntaxNodeScrollBehavior,
 1426    bool,
 1427);
 1428
 1429#[derive(Default)]
 1430struct SelectSyntaxNodeHistory {
 1431    stack: Vec<SelectSyntaxNodeHistoryState>,
 1432    // disable temporarily to allow changing selections without losing the stack
 1433    pub disable_clearing: bool,
 1434}
 1435
 1436impl SelectSyntaxNodeHistory {
 1437    pub fn try_clear(&mut self) {
 1438        if !self.disable_clearing {
 1439            self.stack.clear();
 1440        }
 1441    }
 1442
 1443    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1444        self.stack.push(selection);
 1445    }
 1446
 1447    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1448        self.stack.pop()
 1449    }
 1450}
 1451
 1452enum SelectSyntaxNodeScrollBehavior {
 1453    CursorTop,
 1454    FitSelection,
 1455    CursorBottom,
 1456}
 1457
 1458#[derive(Debug)]
 1459pub(crate) struct NavigationData {
 1460    cursor_anchor: Anchor,
 1461    cursor_position: Point,
 1462    scroll_anchor: ScrollAnchor,
 1463    scroll_top_row: u32,
 1464}
 1465
 1466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1467pub enum GotoDefinitionKind {
 1468    Symbol,
 1469    Declaration,
 1470    Type,
 1471    Implementation,
 1472}
 1473
 1474#[derive(Debug, Clone)]
 1475enum InlayHintRefreshReason {
 1476    ModifiersChanged(bool),
 1477    Toggle(bool),
 1478    SettingsChange(InlayHintSettings),
 1479    NewLinesShown,
 1480    BufferEdited(HashSet<Arc<Language>>),
 1481    RefreshRequested,
 1482    ExcerptsRemoved(Vec<ExcerptId>),
 1483}
 1484
 1485impl InlayHintRefreshReason {
 1486    fn description(&self) -> &'static str {
 1487        match self {
 1488            Self::ModifiersChanged(_) => "modifiers changed",
 1489            Self::Toggle(_) => "toggle",
 1490            Self::SettingsChange(_) => "settings change",
 1491            Self::NewLinesShown => "new lines shown",
 1492            Self::BufferEdited(_) => "buffer edited",
 1493            Self::RefreshRequested => "refresh requested",
 1494            Self::ExcerptsRemoved(_) => "excerpts removed",
 1495        }
 1496    }
 1497}
 1498
 1499pub enum FormatTarget {
 1500    Buffers,
 1501    Ranges(Vec<Range<MultiBufferPoint>>),
 1502}
 1503
 1504pub(crate) struct FocusedBlock {
 1505    id: BlockId,
 1506    focus_handle: WeakFocusHandle,
 1507}
 1508
 1509#[derive(Clone)]
 1510enum JumpData {
 1511    MultiBufferRow {
 1512        row: MultiBufferRow,
 1513        line_offset_from_top: u32,
 1514    },
 1515    MultiBufferPoint {
 1516        excerpt_id: ExcerptId,
 1517        position: Point,
 1518        anchor: text::Anchor,
 1519        line_offset_from_top: u32,
 1520    },
 1521}
 1522
 1523pub enum MultibufferSelectionMode {
 1524    First,
 1525    All,
 1526}
 1527
 1528#[derive(Clone, Copy, Debug, Default)]
 1529pub struct RewrapOptions {
 1530    pub override_language_settings: bool,
 1531    pub preserve_existing_whitespace: bool,
 1532}
 1533
 1534impl Editor {
 1535    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1536        let buffer = cx.new(|cx| Buffer::local("", cx));
 1537        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1538        Self::new(
 1539            EditorMode::SingleLine { auto_width: false },
 1540            buffer,
 1541            None,
 1542            window,
 1543            cx,
 1544        )
 1545    }
 1546
 1547    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1548        let buffer = cx.new(|cx| Buffer::local("", cx));
 1549        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1550        Self::new(EditorMode::full(), buffer, None, window, cx)
 1551    }
 1552
 1553    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1554        let buffer = cx.new(|cx| Buffer::local("", cx));
 1555        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1556        Self::new(
 1557            EditorMode::SingleLine { auto_width: true },
 1558            buffer,
 1559            None,
 1560            window,
 1561            cx,
 1562        )
 1563    }
 1564
 1565    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1566        let buffer = cx.new(|cx| Buffer::local("", cx));
 1567        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1568        Self::new(
 1569            EditorMode::AutoHeight { max_lines },
 1570            buffer,
 1571            None,
 1572            window,
 1573            cx,
 1574        )
 1575    }
 1576
 1577    pub fn for_buffer(
 1578        buffer: Entity<Buffer>,
 1579        project: Option<Entity<Project>>,
 1580        window: &mut Window,
 1581        cx: &mut Context<Self>,
 1582    ) -> Self {
 1583        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1584        Self::new(EditorMode::full(), buffer, project, window, cx)
 1585    }
 1586
 1587    pub fn for_multibuffer(
 1588        buffer: Entity<MultiBuffer>,
 1589        project: Option<Entity<Project>>,
 1590        window: &mut Window,
 1591        cx: &mut Context<Self>,
 1592    ) -> Self {
 1593        Self::new(EditorMode::full(), buffer, project, window, cx)
 1594    }
 1595
 1596    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1597        let mut clone = Self::new(
 1598            self.mode.clone(),
 1599            self.buffer.clone(),
 1600            self.project.clone(),
 1601            window,
 1602            cx,
 1603        );
 1604        self.display_map.update(cx, |display_map, cx| {
 1605            let snapshot = display_map.snapshot(cx);
 1606            clone.display_map.update(cx, |display_map, cx| {
 1607                display_map.set_state(&snapshot, cx);
 1608            });
 1609        });
 1610        clone.folds_did_change(cx);
 1611        clone.selections.clone_state(&self.selections);
 1612        clone.scroll_manager.clone_state(&self.scroll_manager);
 1613        clone.searchable = self.searchable;
 1614        clone.read_only = self.read_only;
 1615        clone
 1616    }
 1617
 1618    pub fn new(
 1619        mode: EditorMode,
 1620        buffer: Entity<MultiBuffer>,
 1621        project: Option<Entity<Project>>,
 1622        window: &mut Window,
 1623        cx: &mut Context<Self>,
 1624    ) -> Self {
 1625        Editor::new_internal(mode, buffer, project, None, window, cx)
 1626    }
 1627
 1628    fn new_internal(
 1629        mode: EditorMode,
 1630        buffer: Entity<MultiBuffer>,
 1631        project: Option<Entity<Project>>,
 1632        display_map: Option<Entity<DisplayMap>>,
 1633        window: &mut Window,
 1634        cx: &mut Context<Self>,
 1635    ) -> Self {
 1636        debug_assert!(
 1637            display_map.is_none() || mode.is_minimap(),
 1638            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1639        );
 1640
 1641        let full_mode = mode.is_full();
 1642        let diagnostics_max_severity = if full_mode {
 1643            EditorSettings::get_global(cx)
 1644                .diagnostics_max_severity
 1645                .unwrap_or(DiagnosticSeverity::Hint)
 1646        } else {
 1647            DiagnosticSeverity::Off
 1648        };
 1649        let style = window.text_style();
 1650        let font_size = style.font_size.to_pixels(window.rem_size());
 1651        let editor = cx.entity().downgrade();
 1652        let fold_placeholder = FoldPlaceholder {
 1653            constrain_width: true,
 1654            render: Arc::new(move |fold_id, fold_range, cx| {
 1655                let editor = editor.clone();
 1656                div()
 1657                    .id(fold_id)
 1658                    .bg(cx.theme().colors().ghost_element_background)
 1659                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1660                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1661                    .rounded_xs()
 1662                    .size_full()
 1663                    .cursor_pointer()
 1664                    .child("")
 1665                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1666                    .on_click(move |_, _window, cx| {
 1667                        editor
 1668                            .update(cx, |editor, cx| {
 1669                                editor.unfold_ranges(
 1670                                    &[fold_range.start..fold_range.end],
 1671                                    true,
 1672                                    false,
 1673                                    cx,
 1674                                );
 1675                                cx.stop_propagation();
 1676                            })
 1677                            .ok();
 1678                    })
 1679                    .into_any()
 1680            }),
 1681            merge_adjacent: true,
 1682            ..FoldPlaceholder::default()
 1683        };
 1684        let display_map = display_map.unwrap_or_else(|| {
 1685            cx.new(|cx| {
 1686                DisplayMap::new(
 1687                    buffer.clone(),
 1688                    style.font(),
 1689                    font_size,
 1690                    None,
 1691                    FILE_HEADER_HEIGHT,
 1692                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1693                    fold_placeholder,
 1694                    diagnostics_max_severity,
 1695                    cx,
 1696                )
 1697            })
 1698        });
 1699
 1700        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1701
 1702        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1703
 1704        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1705            .then(|| language_settings::SoftWrap::None);
 1706
 1707        let mut project_subscriptions = Vec::new();
 1708        if mode.is_full() {
 1709            if let Some(project) = project.as_ref() {
 1710                project_subscriptions.push(cx.subscribe_in(
 1711                    project,
 1712                    window,
 1713                    |editor, _, event, window, cx| match event {
 1714                        project::Event::RefreshCodeLens => {
 1715                            // we always query lens with actions, without storing them, always refreshing them
 1716                        }
 1717                        project::Event::RefreshInlayHints => {
 1718                            editor
 1719                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1720                        }
 1721                        project::Event::LanguageServerAdded(..)
 1722                        | project::Event::LanguageServerRemoved(..) => {
 1723                            if editor.tasks_update_task.is_none() {
 1724                                editor.tasks_update_task =
 1725                                    Some(editor.refresh_runnables(window, cx));
 1726                            }
 1727                            editor.pull_diagnostics(None, window, cx);
 1728                        }
 1729                        project::Event::SnippetEdit(id, snippet_edits) => {
 1730                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1731                                let focus_handle = editor.focus_handle(cx);
 1732                                if focus_handle.is_focused(window) {
 1733                                    let snapshot = buffer.read(cx).snapshot();
 1734                                    for (range, snippet) in snippet_edits {
 1735                                        let editor_range =
 1736                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1737                                        editor
 1738                                            .insert_snippet(
 1739                                                &[editor_range],
 1740                                                snippet.clone(),
 1741                                                window,
 1742                                                cx,
 1743                                            )
 1744                                            .ok();
 1745                                    }
 1746                                }
 1747                            }
 1748                        }
 1749                        _ => {}
 1750                    },
 1751                ));
 1752                if let Some(task_inventory) = project
 1753                    .read(cx)
 1754                    .task_store()
 1755                    .read(cx)
 1756                    .task_inventory()
 1757                    .cloned()
 1758                {
 1759                    project_subscriptions.push(cx.observe_in(
 1760                        &task_inventory,
 1761                        window,
 1762                        |editor, _, window, cx| {
 1763                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1764                        },
 1765                    ));
 1766                };
 1767
 1768                project_subscriptions.push(cx.subscribe_in(
 1769                    &project.read(cx).breakpoint_store(),
 1770                    window,
 1771                    |editor, _, event, window, cx| match event {
 1772                        BreakpointStoreEvent::ClearDebugLines => {
 1773                            editor.clear_row_highlights::<ActiveDebugLine>();
 1774                            editor.refresh_inline_values(cx);
 1775                        }
 1776                        BreakpointStoreEvent::SetDebugLine => {
 1777                            if editor.go_to_active_debug_line(window, cx) {
 1778                                cx.stop_propagation();
 1779                            }
 1780
 1781                            editor.refresh_inline_values(cx);
 1782                        }
 1783                        _ => {}
 1784                    },
 1785                ));
 1786            }
 1787        }
 1788
 1789        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1790
 1791        let inlay_hint_settings =
 1792            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1793        let focus_handle = cx.focus_handle();
 1794        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1795            .detach();
 1796        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1797            .detach();
 1798        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1799            .detach();
 1800        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1801            .detach();
 1802        cx.observe_pending_input(window, Self::observe_pending_input)
 1803            .detach();
 1804
 1805        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1806            Some(false)
 1807        } else {
 1808            None
 1809        };
 1810
 1811        let breakpoint_store = match (&mode, project.as_ref()) {
 1812            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1813            _ => None,
 1814        };
 1815
 1816        let mut code_action_providers = Vec::new();
 1817        let mut load_uncommitted_diff = None;
 1818        if let Some(project) = project.clone() {
 1819            load_uncommitted_diff = Some(
 1820                update_uncommitted_diff_for_buffer(
 1821                    cx.entity(),
 1822                    &project,
 1823                    buffer.read(cx).all_buffers(),
 1824                    buffer.clone(),
 1825                    cx,
 1826                )
 1827                .shared(),
 1828            );
 1829            code_action_providers.push(Rc::new(project) as Rc<_>);
 1830        }
 1831
 1832        let mut editor = Self {
 1833            focus_handle,
 1834            show_cursor_when_unfocused: false,
 1835            last_focused_descendant: None,
 1836            buffer: buffer.clone(),
 1837            display_map: display_map.clone(),
 1838            selections,
 1839            scroll_manager: ScrollManager::new(cx),
 1840            columnar_selection_tail: None,
 1841            columnar_display_point: None,
 1842            add_selections_state: None,
 1843            select_next_state: None,
 1844            select_prev_state: None,
 1845            selection_history: SelectionHistory::default(),
 1846            defer_selection_effects: false,
 1847            deferred_selection_effects_state: None,
 1848            autoclose_regions: Vec::new(),
 1849            snippet_stack: InvalidationStack::default(),
 1850            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1851            ime_transaction: None,
 1852            active_diagnostics: ActiveDiagnostic::None,
 1853            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1854            inline_diagnostics_update: Task::ready(()),
 1855            inline_diagnostics: Vec::new(),
 1856            soft_wrap_mode_override,
 1857            diagnostics_max_severity,
 1858            hard_wrap: None,
 1859            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1860            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1861            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1862            project,
 1863            blink_manager: blink_manager.clone(),
 1864            show_local_selections: true,
 1865            show_scrollbars: ScrollbarAxes {
 1866                horizontal: full_mode,
 1867                vertical: full_mode,
 1868            },
 1869            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1870            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1871            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1872            show_gutter: mode.is_full(),
 1873            show_line_numbers: None,
 1874            use_relative_line_numbers: None,
 1875            disable_expand_excerpt_buttons: false,
 1876            show_git_diff_gutter: None,
 1877            show_code_actions: None,
 1878            show_runnables: None,
 1879            show_breakpoints: None,
 1880            show_wrap_guides: None,
 1881            show_indent_guides,
 1882            placeholder_text: None,
 1883            highlight_order: 0,
 1884            highlighted_rows: HashMap::default(),
 1885            background_highlights: TreeMap::default(),
 1886            gutter_highlights: TreeMap::default(),
 1887            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1888            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1889            nav_history: None,
 1890            context_menu: RefCell::new(None),
 1891            context_menu_options: None,
 1892            mouse_context_menu: None,
 1893            completion_tasks: Vec::new(),
 1894            inline_blame_popover: None,
 1895            signature_help_state: SignatureHelpState::default(),
 1896            auto_signature_help: None,
 1897            find_all_references_task_sources: Vec::new(),
 1898            next_completion_id: 0,
 1899            next_inlay_id: 0,
 1900            code_action_providers,
 1901            available_code_actions: None,
 1902            code_actions_task: None,
 1903            quick_selection_highlight_task: None,
 1904            debounced_selection_highlight_task: None,
 1905            document_highlights_task: None,
 1906            linked_editing_range_task: None,
 1907            pending_rename: None,
 1908            searchable: true,
 1909            cursor_shape: EditorSettings::get_global(cx)
 1910                .cursor_shape
 1911                .unwrap_or_default(),
 1912            current_line_highlight: None,
 1913            autoindent_mode: Some(AutoindentMode::EachLine),
 1914            collapse_matches: false,
 1915            workspace: None,
 1916            input_enabled: true,
 1917            use_modal_editing: mode.is_full(),
 1918            read_only: mode.is_minimap(),
 1919            use_autoclose: true,
 1920            use_auto_surround: true,
 1921            auto_replace_emoji_shortcode: false,
 1922            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1923            leader_id: None,
 1924            remote_id: None,
 1925            hover_state: HoverState::default(),
 1926            pending_mouse_down: None,
 1927            hovered_link_state: None,
 1928            edit_prediction_provider: None,
 1929            active_inline_completion: None,
 1930            stale_inline_completion_in_menu: None,
 1931            edit_prediction_preview: EditPredictionPreview::Inactive {
 1932                released_too_fast: false,
 1933            },
 1934            inline_diagnostics_enabled: mode.is_full(),
 1935            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1936            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1937
 1938            gutter_hovered: false,
 1939            pixel_position_of_newest_cursor: None,
 1940            last_bounds: None,
 1941            last_position_map: None,
 1942            expect_bounds_change: None,
 1943            gutter_dimensions: GutterDimensions::default(),
 1944            style: None,
 1945            show_cursor_names: false,
 1946            hovered_cursors: HashMap::default(),
 1947            next_editor_action_id: EditorActionId::default(),
 1948            editor_actions: Rc::default(),
 1949            inline_completions_hidden_for_vim_mode: false,
 1950            show_inline_completions_override: None,
 1951            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1952            edit_prediction_settings: EditPredictionSettings::Disabled,
 1953            edit_prediction_indent_conflict: false,
 1954            edit_prediction_requires_modifier_in_indent_conflict: true,
 1955            custom_context_menu: None,
 1956            show_git_blame_gutter: false,
 1957            show_git_blame_inline: false,
 1958            show_selection_menu: None,
 1959            show_git_blame_inline_delay_task: None,
 1960            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1961            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1962            serialize_dirty_buffers: !mode.is_minimap()
 1963                && ProjectSettings::get_global(cx)
 1964                    .session
 1965                    .restore_unsaved_buffers,
 1966            blame: None,
 1967            blame_subscription: None,
 1968            tasks: BTreeMap::default(),
 1969
 1970            breakpoint_store,
 1971            gutter_breakpoint_indicator: (None, None),
 1972            _subscriptions: vec![
 1973                cx.observe(&buffer, Self::on_buffer_changed),
 1974                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1975                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1976                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1977                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1978                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1979                cx.observe_window_activation(window, |editor, window, cx| {
 1980                    let active = window.is_window_active();
 1981                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1982                        if active {
 1983                            blink_manager.enable(cx);
 1984                        } else {
 1985                            blink_manager.disable(cx);
 1986                        }
 1987                    });
 1988                    if active {
 1989                        editor.show_mouse_cursor();
 1990                    }
 1991                }),
 1992            ],
 1993            tasks_update_task: None,
 1994            pull_diagnostics_task: Task::ready(()),
 1995            linked_edit_ranges: Default::default(),
 1996            in_project_search: false,
 1997            previous_search_ranges: None,
 1998            breadcrumb_header: None,
 1999            focused_block: None,
 2000            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2001            addons: HashMap::default(),
 2002            registered_buffers: HashMap::default(),
 2003            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2004            selection_mark_mode: false,
 2005            toggle_fold_multiple_buffers: Task::ready(()),
 2006            serialize_selections: Task::ready(()),
 2007            serialize_folds: Task::ready(()),
 2008            text_style_refinement: None,
 2009            load_diff_task: load_uncommitted_diff,
 2010            temporary_diff_override: false,
 2011            mouse_cursor_hidden: false,
 2012            minimap: None,
 2013            hide_mouse_mode: EditorSettings::get_global(cx)
 2014                .hide_mouse
 2015                .unwrap_or_default(),
 2016            change_list: ChangeList::new(),
 2017            mode,
 2018            selection_drag_state: SelectionDragState::None,
 2019            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2020        };
 2021        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2022            editor
 2023                ._subscriptions
 2024                .push(cx.observe(breakpoints, |_, _, cx| {
 2025                    cx.notify();
 2026                }));
 2027        }
 2028        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2029        editor._subscriptions.extend(project_subscriptions);
 2030
 2031        editor._subscriptions.push(cx.subscribe_in(
 2032            &cx.entity(),
 2033            window,
 2034            |editor, _, e: &EditorEvent, window, cx| match e {
 2035                EditorEvent::ScrollPositionChanged { local, .. } => {
 2036                    if *local {
 2037                        let new_anchor = editor.scroll_manager.anchor();
 2038                        let snapshot = editor.snapshot(window, cx);
 2039                        editor.update_restoration_data(cx, move |data| {
 2040                            data.scroll_position = (
 2041                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2042                                new_anchor.offset,
 2043                            );
 2044                        });
 2045                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2046                        editor.inline_blame_popover.take();
 2047                    }
 2048                }
 2049                EditorEvent::Edited { .. } => {
 2050                    if !vim_enabled(cx) {
 2051                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2052                        let pop_state = editor
 2053                            .change_list
 2054                            .last()
 2055                            .map(|previous| {
 2056                                previous.len() == selections.len()
 2057                                    && previous.iter().enumerate().all(|(ix, p)| {
 2058                                        p.to_display_point(&map).row()
 2059                                            == selections[ix].head().row()
 2060                                    })
 2061                            })
 2062                            .unwrap_or(false);
 2063                        let new_positions = selections
 2064                            .into_iter()
 2065                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2066                            .collect();
 2067                        editor
 2068                            .change_list
 2069                            .push_to_change_list(pop_state, new_positions);
 2070                    }
 2071                }
 2072                _ => (),
 2073            },
 2074        ));
 2075
 2076        if let Some(dap_store) = editor
 2077            .project
 2078            .as_ref()
 2079            .map(|project| project.read(cx).dap_store())
 2080        {
 2081            let weak_editor = cx.weak_entity();
 2082
 2083            editor
 2084                ._subscriptions
 2085                .push(
 2086                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2087                        let session_entity = cx.entity();
 2088                        weak_editor
 2089                            .update(cx, |editor, cx| {
 2090                                editor._subscriptions.push(
 2091                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2092                                );
 2093                            })
 2094                            .ok();
 2095                    }),
 2096                );
 2097
 2098            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2099                editor
 2100                    ._subscriptions
 2101                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2102            }
 2103        }
 2104
 2105        // skip adding the initial selection to selection history
 2106        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2107        editor.end_selection(window, cx);
 2108        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2109
 2110        editor.scroll_manager.show_scrollbars(window, cx);
 2111        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2112
 2113        if full_mode {
 2114            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2115            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2116
 2117            if editor.git_blame_inline_enabled {
 2118                editor.start_git_blame_inline(false, window, cx);
 2119            }
 2120
 2121            editor.go_to_active_debug_line(window, cx);
 2122
 2123            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2124                if let Some(project) = editor.project.as_ref() {
 2125                    let handle = project.update(cx, |project, cx| {
 2126                        project.register_buffer_with_language_servers(&buffer, cx)
 2127                    });
 2128                    editor
 2129                        .registered_buffers
 2130                        .insert(buffer.read(cx).remote_id(), handle);
 2131                }
 2132            }
 2133
 2134            editor.minimap =
 2135                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2136            editor.pull_diagnostics(None, window, cx);
 2137        }
 2138
 2139        editor.report_editor_event("Editor Opened", None, cx);
 2140        editor
 2141    }
 2142
 2143    pub fn deploy_mouse_context_menu(
 2144        &mut self,
 2145        position: gpui::Point<Pixels>,
 2146        context_menu: Entity<ContextMenu>,
 2147        window: &mut Window,
 2148        cx: &mut Context<Self>,
 2149    ) {
 2150        self.mouse_context_menu = Some(MouseContextMenu::new(
 2151            self,
 2152            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2153            context_menu,
 2154            window,
 2155            cx,
 2156        ));
 2157    }
 2158
 2159    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2160        self.mouse_context_menu
 2161            .as_ref()
 2162            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2163    }
 2164
 2165    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2166        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2167    }
 2168
 2169    fn key_context_internal(
 2170        &self,
 2171        has_active_edit_prediction: bool,
 2172        window: &Window,
 2173        cx: &App,
 2174    ) -> KeyContext {
 2175        let mut key_context = KeyContext::new_with_defaults();
 2176        key_context.add("Editor");
 2177        let mode = match self.mode {
 2178            EditorMode::SingleLine { .. } => "single_line",
 2179            EditorMode::AutoHeight { .. } => "auto_height",
 2180            EditorMode::Minimap { .. } => "minimap",
 2181            EditorMode::Full { .. } => "full",
 2182        };
 2183
 2184        if EditorSettings::jupyter_enabled(cx) {
 2185            key_context.add("jupyter");
 2186        }
 2187
 2188        key_context.set("mode", mode);
 2189        if self.pending_rename.is_some() {
 2190            key_context.add("renaming");
 2191        }
 2192
 2193        match self.context_menu.borrow().as_ref() {
 2194            Some(CodeContextMenu::Completions(_)) => {
 2195                key_context.add("menu");
 2196                key_context.add("showing_completions");
 2197            }
 2198            Some(CodeContextMenu::CodeActions(_)) => {
 2199                key_context.add("menu");
 2200                key_context.add("showing_code_actions")
 2201            }
 2202            None => {}
 2203        }
 2204
 2205        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2206        if !self.focus_handle(cx).contains_focused(window, cx)
 2207            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2208        {
 2209            for addon in self.addons.values() {
 2210                addon.extend_key_context(&mut key_context, cx)
 2211            }
 2212        }
 2213
 2214        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2215            if let Some(extension) = singleton_buffer
 2216                .read(cx)
 2217                .file()
 2218                .and_then(|file| file.path().extension()?.to_str())
 2219            {
 2220                key_context.set("extension", extension.to_string());
 2221            }
 2222        } else {
 2223            key_context.add("multibuffer");
 2224        }
 2225
 2226        if has_active_edit_prediction {
 2227            if self.edit_prediction_in_conflict() {
 2228                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2229            } else {
 2230                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2231                key_context.add("copilot_suggestion");
 2232            }
 2233        }
 2234
 2235        if self.selection_mark_mode {
 2236            key_context.add("selection_mode");
 2237        }
 2238
 2239        key_context
 2240    }
 2241
 2242    fn show_mouse_cursor(&mut self) {
 2243        self.mouse_cursor_hidden = false;
 2244    }
 2245
 2246    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2247        self.mouse_cursor_hidden = match origin {
 2248            HideMouseCursorOrigin::TypingAction => {
 2249                matches!(
 2250                    self.hide_mouse_mode,
 2251                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2252                )
 2253            }
 2254            HideMouseCursorOrigin::MovementAction => {
 2255                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2256            }
 2257        };
 2258    }
 2259
 2260    pub fn edit_prediction_in_conflict(&self) -> bool {
 2261        if !self.show_edit_predictions_in_menu() {
 2262            return false;
 2263        }
 2264
 2265        let showing_completions = self
 2266            .context_menu
 2267            .borrow()
 2268            .as_ref()
 2269            .map_or(false, |context| {
 2270                matches!(context, CodeContextMenu::Completions(_))
 2271            });
 2272
 2273        showing_completions
 2274            || self.edit_prediction_requires_modifier()
 2275            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2276            // bindings to insert tab characters.
 2277            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2278    }
 2279
 2280    pub fn accept_edit_prediction_keybind(
 2281        &self,
 2282        accept_partial: bool,
 2283        window: &Window,
 2284        cx: &App,
 2285    ) -> AcceptEditPredictionBinding {
 2286        let key_context = self.key_context_internal(true, window, cx);
 2287        let in_conflict = self.edit_prediction_in_conflict();
 2288
 2289        let bindings = if accept_partial {
 2290            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2291        } else {
 2292            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2293        };
 2294
 2295        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2296        // just the first one.
 2297        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2298            !in_conflict
 2299                || binding
 2300                    .keystrokes()
 2301                    .first()
 2302                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2303        }))
 2304    }
 2305
 2306    pub fn new_file(
 2307        workspace: &mut Workspace,
 2308        _: &workspace::NewFile,
 2309        window: &mut Window,
 2310        cx: &mut Context<Workspace>,
 2311    ) {
 2312        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2313            "Failed to create buffer",
 2314            window,
 2315            cx,
 2316            |e, _, _| match e.error_code() {
 2317                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2318                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2319                e.error_tag("required").unwrap_or("the latest version")
 2320            )),
 2321                _ => None,
 2322            },
 2323        );
 2324    }
 2325
 2326    pub fn new_in_workspace(
 2327        workspace: &mut Workspace,
 2328        window: &mut Window,
 2329        cx: &mut Context<Workspace>,
 2330    ) -> Task<Result<Entity<Editor>>> {
 2331        let project = workspace.project().clone();
 2332        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2333
 2334        cx.spawn_in(window, async move |workspace, cx| {
 2335            let buffer = create.await?;
 2336            workspace.update_in(cx, |workspace, window, cx| {
 2337                let editor =
 2338                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2339                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2340                editor
 2341            })
 2342        })
 2343    }
 2344
 2345    fn new_file_vertical(
 2346        workspace: &mut Workspace,
 2347        _: &workspace::NewFileSplitVertical,
 2348        window: &mut Window,
 2349        cx: &mut Context<Workspace>,
 2350    ) {
 2351        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2352    }
 2353
 2354    fn new_file_horizontal(
 2355        workspace: &mut Workspace,
 2356        _: &workspace::NewFileSplitHorizontal,
 2357        window: &mut Window,
 2358        cx: &mut Context<Workspace>,
 2359    ) {
 2360        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2361    }
 2362
 2363    fn new_file_in_direction(
 2364        workspace: &mut Workspace,
 2365        direction: SplitDirection,
 2366        window: &mut Window,
 2367        cx: &mut Context<Workspace>,
 2368    ) {
 2369        let project = workspace.project().clone();
 2370        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2371
 2372        cx.spawn_in(window, async move |workspace, cx| {
 2373            let buffer = create.await?;
 2374            workspace.update_in(cx, move |workspace, window, cx| {
 2375                workspace.split_item(
 2376                    direction,
 2377                    Box::new(
 2378                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2379                    ),
 2380                    window,
 2381                    cx,
 2382                )
 2383            })?;
 2384            anyhow::Ok(())
 2385        })
 2386        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2387            match e.error_code() {
 2388                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2389                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2390                e.error_tag("required").unwrap_or("the latest version")
 2391            )),
 2392                _ => None,
 2393            }
 2394        });
 2395    }
 2396
 2397    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2398        self.leader_id
 2399    }
 2400
 2401    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2402        &self.buffer
 2403    }
 2404
 2405    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2406        self.workspace.as_ref()?.0.upgrade()
 2407    }
 2408
 2409    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2410        self.buffer().read(cx).title(cx)
 2411    }
 2412
 2413    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2414        let git_blame_gutter_max_author_length = self
 2415            .render_git_blame_gutter(cx)
 2416            .then(|| {
 2417                if let Some(blame) = self.blame.as_ref() {
 2418                    let max_author_length =
 2419                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2420                    Some(max_author_length)
 2421                } else {
 2422                    None
 2423                }
 2424            })
 2425            .flatten();
 2426
 2427        EditorSnapshot {
 2428            mode: self.mode.clone(),
 2429            show_gutter: self.show_gutter,
 2430            show_line_numbers: self.show_line_numbers,
 2431            show_git_diff_gutter: self.show_git_diff_gutter,
 2432            show_code_actions: self.show_code_actions,
 2433            show_runnables: self.show_runnables,
 2434            show_breakpoints: self.show_breakpoints,
 2435            git_blame_gutter_max_author_length,
 2436            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2437            scroll_anchor: self.scroll_manager.anchor(),
 2438            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2439            placeholder_text: self.placeholder_text.clone(),
 2440            is_focused: self.focus_handle.is_focused(window),
 2441            current_line_highlight: self
 2442                .current_line_highlight
 2443                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2444            gutter_hovered: self.gutter_hovered,
 2445        }
 2446    }
 2447
 2448    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2449        self.buffer.read(cx).language_at(point, cx)
 2450    }
 2451
 2452    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2453        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2454    }
 2455
 2456    pub fn active_excerpt(
 2457        &self,
 2458        cx: &App,
 2459    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2460        self.buffer
 2461            .read(cx)
 2462            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2463    }
 2464
 2465    pub fn mode(&self) -> &EditorMode {
 2466        &self.mode
 2467    }
 2468
 2469    pub fn set_mode(&mut self, mode: EditorMode) {
 2470        self.mode = mode;
 2471    }
 2472
 2473    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2474        self.collaboration_hub.as_deref()
 2475    }
 2476
 2477    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2478        self.collaboration_hub = Some(hub);
 2479    }
 2480
 2481    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2482        self.in_project_search = in_project_search;
 2483    }
 2484
 2485    pub fn set_custom_context_menu(
 2486        &mut self,
 2487        f: impl 'static
 2488        + Fn(
 2489            &mut Self,
 2490            DisplayPoint,
 2491            &mut Window,
 2492            &mut Context<Self>,
 2493        ) -> Option<Entity<ui::ContextMenu>>,
 2494    ) {
 2495        self.custom_context_menu = Some(Box::new(f))
 2496    }
 2497
 2498    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2499        self.completion_provider = provider;
 2500    }
 2501
 2502    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2503        self.semantics_provider.clone()
 2504    }
 2505
 2506    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2507        self.semantics_provider = provider;
 2508    }
 2509
 2510    pub fn set_edit_prediction_provider<T>(
 2511        &mut self,
 2512        provider: Option<Entity<T>>,
 2513        window: &mut Window,
 2514        cx: &mut Context<Self>,
 2515    ) where
 2516        T: EditPredictionProvider,
 2517    {
 2518        self.edit_prediction_provider =
 2519            provider.map(|provider| RegisteredInlineCompletionProvider {
 2520                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2521                    if this.focus_handle.is_focused(window) {
 2522                        this.update_visible_inline_completion(window, cx);
 2523                    }
 2524                }),
 2525                provider: Arc::new(provider),
 2526            });
 2527        self.update_edit_prediction_settings(cx);
 2528        self.refresh_inline_completion(false, false, window, cx);
 2529    }
 2530
 2531    pub fn placeholder_text(&self) -> Option<&str> {
 2532        self.placeholder_text.as_deref()
 2533    }
 2534
 2535    pub fn set_placeholder_text(
 2536        &mut self,
 2537        placeholder_text: impl Into<Arc<str>>,
 2538        cx: &mut Context<Self>,
 2539    ) {
 2540        let placeholder_text = Some(placeholder_text.into());
 2541        if self.placeholder_text != placeholder_text {
 2542            self.placeholder_text = placeholder_text;
 2543            cx.notify();
 2544        }
 2545    }
 2546
 2547    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2548        self.cursor_shape = cursor_shape;
 2549
 2550        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2551        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2552
 2553        cx.notify();
 2554    }
 2555
 2556    pub fn set_current_line_highlight(
 2557        &mut self,
 2558        current_line_highlight: Option<CurrentLineHighlight>,
 2559    ) {
 2560        self.current_line_highlight = current_line_highlight;
 2561    }
 2562
 2563    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2564        self.collapse_matches = collapse_matches;
 2565    }
 2566
 2567    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2568        let buffers = self.buffer.read(cx).all_buffers();
 2569        let Some(project) = self.project.as_ref() else {
 2570            return;
 2571        };
 2572        project.update(cx, |project, cx| {
 2573            for buffer in buffers {
 2574                self.registered_buffers
 2575                    .entry(buffer.read(cx).remote_id())
 2576                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2577            }
 2578        })
 2579    }
 2580
 2581    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2582        if self.collapse_matches {
 2583            return range.start..range.start;
 2584        }
 2585        range.clone()
 2586    }
 2587
 2588    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2589        if self.display_map.read(cx).clip_at_line_ends != clip {
 2590            self.display_map
 2591                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2592        }
 2593    }
 2594
 2595    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2596        self.input_enabled = input_enabled;
 2597    }
 2598
 2599    pub fn set_inline_completions_hidden_for_vim_mode(
 2600        &mut self,
 2601        hidden: bool,
 2602        window: &mut Window,
 2603        cx: &mut Context<Self>,
 2604    ) {
 2605        if hidden != self.inline_completions_hidden_for_vim_mode {
 2606            self.inline_completions_hidden_for_vim_mode = hidden;
 2607            if hidden {
 2608                self.update_visible_inline_completion(window, cx);
 2609            } else {
 2610                self.refresh_inline_completion(true, false, window, cx);
 2611            }
 2612        }
 2613    }
 2614
 2615    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2616        self.menu_inline_completions_policy = value;
 2617    }
 2618
 2619    pub fn set_autoindent(&mut self, autoindent: bool) {
 2620        if autoindent {
 2621            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2622        } else {
 2623            self.autoindent_mode = None;
 2624        }
 2625    }
 2626
 2627    pub fn read_only(&self, cx: &App) -> bool {
 2628        self.read_only || self.buffer.read(cx).read_only()
 2629    }
 2630
 2631    pub fn set_read_only(&mut self, read_only: bool) {
 2632        self.read_only = read_only;
 2633    }
 2634
 2635    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2636        self.use_autoclose = autoclose;
 2637    }
 2638
 2639    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2640        self.use_auto_surround = auto_surround;
 2641    }
 2642
 2643    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2644        self.auto_replace_emoji_shortcode = auto_replace;
 2645    }
 2646
 2647    pub fn toggle_edit_predictions(
 2648        &mut self,
 2649        _: &ToggleEditPrediction,
 2650        window: &mut Window,
 2651        cx: &mut Context<Self>,
 2652    ) {
 2653        if self.show_inline_completions_override.is_some() {
 2654            self.set_show_edit_predictions(None, window, cx);
 2655        } else {
 2656            let show_edit_predictions = !self.edit_predictions_enabled();
 2657            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2658        }
 2659    }
 2660
 2661    pub fn set_show_edit_predictions(
 2662        &mut self,
 2663        show_edit_predictions: Option<bool>,
 2664        window: &mut Window,
 2665        cx: &mut Context<Self>,
 2666    ) {
 2667        self.show_inline_completions_override = show_edit_predictions;
 2668        self.update_edit_prediction_settings(cx);
 2669
 2670        if let Some(false) = show_edit_predictions {
 2671            self.discard_inline_completion(false, cx);
 2672        } else {
 2673            self.refresh_inline_completion(false, true, window, cx);
 2674        }
 2675    }
 2676
 2677    fn inline_completions_disabled_in_scope(
 2678        &self,
 2679        buffer: &Entity<Buffer>,
 2680        buffer_position: language::Anchor,
 2681        cx: &App,
 2682    ) -> bool {
 2683        let snapshot = buffer.read(cx).snapshot();
 2684        let settings = snapshot.settings_at(buffer_position, cx);
 2685
 2686        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2687            return false;
 2688        };
 2689
 2690        scope.override_name().map_or(false, |scope_name| {
 2691            settings
 2692                .edit_predictions_disabled_in
 2693                .iter()
 2694                .any(|s| s == scope_name)
 2695        })
 2696    }
 2697
 2698    pub fn set_use_modal_editing(&mut self, to: bool) {
 2699        self.use_modal_editing = to;
 2700    }
 2701
 2702    pub fn use_modal_editing(&self) -> bool {
 2703        self.use_modal_editing
 2704    }
 2705
 2706    fn selections_did_change(
 2707        &mut self,
 2708        local: bool,
 2709        old_cursor_position: &Anchor,
 2710        should_update_completions: bool,
 2711        window: &mut Window,
 2712        cx: &mut Context<Self>,
 2713    ) {
 2714        window.invalidate_character_coordinates();
 2715
 2716        // Copy selections to primary selection buffer
 2717        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2718        if local {
 2719            let selections = self.selections.all::<usize>(cx);
 2720            let buffer_handle = self.buffer.read(cx).read(cx);
 2721
 2722            let mut text = String::new();
 2723            for (index, selection) in selections.iter().enumerate() {
 2724                let text_for_selection = buffer_handle
 2725                    .text_for_range(selection.start..selection.end)
 2726                    .collect::<String>();
 2727
 2728                text.push_str(&text_for_selection);
 2729                if index != selections.len() - 1 {
 2730                    text.push('\n');
 2731                }
 2732            }
 2733
 2734            if !text.is_empty() {
 2735                cx.write_to_primary(ClipboardItem::new_string(text));
 2736            }
 2737        }
 2738
 2739        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2740            self.buffer.update(cx, |buffer, cx| {
 2741                buffer.set_active_selections(
 2742                    &self.selections.disjoint_anchors(),
 2743                    self.selections.line_mode,
 2744                    self.cursor_shape,
 2745                    cx,
 2746                )
 2747            });
 2748        }
 2749        let display_map = self
 2750            .display_map
 2751            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2752        let buffer = &display_map.buffer_snapshot;
 2753        if self.selections.count() == 1 {
 2754            self.add_selections_state = None;
 2755        }
 2756        self.select_next_state = None;
 2757        self.select_prev_state = None;
 2758        self.select_syntax_node_history.try_clear();
 2759        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2760        self.snippet_stack
 2761            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2762        self.take_rename(false, window, cx);
 2763
 2764        let newest_selection = self.selections.newest_anchor();
 2765        let new_cursor_position = newest_selection.head();
 2766        let selection_start = newest_selection.start;
 2767
 2768        self.push_to_nav_history(
 2769            *old_cursor_position,
 2770            Some(new_cursor_position.to_point(buffer)),
 2771            false,
 2772            cx,
 2773        );
 2774
 2775        if local {
 2776            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2777                if !self.registered_buffers.contains_key(&buffer_id) {
 2778                    if let Some(project) = self.project.as_ref() {
 2779                        project.update(cx, |project, cx| {
 2780                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2781                                return;
 2782                            };
 2783                            self.registered_buffers.insert(
 2784                                buffer_id,
 2785                                project.register_buffer_with_language_servers(&buffer, cx),
 2786                            );
 2787                        })
 2788                    }
 2789                }
 2790            }
 2791
 2792            let mut context_menu = self.context_menu.borrow_mut();
 2793            let completion_menu = match context_menu.as_ref() {
 2794                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2795                Some(CodeContextMenu::CodeActions(_)) => {
 2796                    *context_menu = None;
 2797                    None
 2798                }
 2799                None => None,
 2800            };
 2801            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2802            drop(context_menu);
 2803
 2804            if should_update_completions {
 2805                if let Some(completion_position) = completion_position {
 2806                    let start_offset = selection_start.to_offset(buffer);
 2807                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2808                    let continue_showing = if position_matches {
 2809                        if self.snippet_stack.is_empty() {
 2810                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2811                        } else {
 2812                            // Snippet choices can be shown even when the cursor is in whitespace.
 2813                            // Dismissing the menu when actions like backspace
 2814                            true
 2815                        }
 2816                    } else {
 2817                        false
 2818                    };
 2819
 2820                    if continue_showing {
 2821                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2822                    } else {
 2823                        self.hide_context_menu(window, cx);
 2824                    }
 2825                }
 2826            }
 2827
 2828            hide_hover(self, cx);
 2829
 2830            if old_cursor_position.to_display_point(&display_map).row()
 2831                != new_cursor_position.to_display_point(&display_map).row()
 2832            {
 2833                self.available_code_actions.take();
 2834            }
 2835            self.refresh_code_actions(window, cx);
 2836            self.refresh_document_highlights(cx);
 2837            self.refresh_selected_text_highlights(false, window, cx);
 2838            refresh_matching_bracket_highlights(self, window, cx);
 2839            self.update_visible_inline_completion(window, cx);
 2840            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2841            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2842            self.inline_blame_popover.take();
 2843            if self.git_blame_inline_enabled {
 2844                self.start_inline_blame_timer(window, cx);
 2845            }
 2846        }
 2847
 2848        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2849        cx.emit(EditorEvent::SelectionsChanged { local });
 2850
 2851        let selections = &self.selections.disjoint;
 2852        if selections.len() == 1 {
 2853            cx.emit(SearchEvent::ActiveMatchChanged)
 2854        }
 2855        if local {
 2856            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2857                let inmemory_selections = selections
 2858                    .iter()
 2859                    .map(|s| {
 2860                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2861                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2862                    })
 2863                    .collect();
 2864                self.update_restoration_data(cx, |data| {
 2865                    data.selections = inmemory_selections;
 2866                });
 2867
 2868                if WorkspaceSettings::get(None, cx).restore_on_startup
 2869                    != RestoreOnStartupBehavior::None
 2870                {
 2871                    if let Some(workspace_id) =
 2872                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2873                    {
 2874                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2875                        let selections = selections.clone();
 2876                        let background_executor = cx.background_executor().clone();
 2877                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2878                        self.serialize_selections = cx.background_spawn(async move {
 2879                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2880                    let db_selections = selections
 2881                        .iter()
 2882                        .map(|selection| {
 2883                            (
 2884                                selection.start.to_offset(&snapshot),
 2885                                selection.end.to_offset(&snapshot),
 2886                            )
 2887                        })
 2888                        .collect();
 2889
 2890                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2891                        .await
 2892                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2893                        .log_err();
 2894                });
 2895                    }
 2896                }
 2897            }
 2898        }
 2899
 2900        cx.notify();
 2901    }
 2902
 2903    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2904        use text::ToOffset as _;
 2905        use text::ToPoint as _;
 2906
 2907        if self.mode.is_minimap()
 2908            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2909        {
 2910            return;
 2911        }
 2912
 2913        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2914            return;
 2915        };
 2916
 2917        let snapshot = singleton.read(cx).snapshot();
 2918        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2919            let display_snapshot = display_map.snapshot(cx);
 2920
 2921            display_snapshot
 2922                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2923                .map(|fold| {
 2924                    fold.range.start.text_anchor.to_point(&snapshot)
 2925                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2926                })
 2927                .collect()
 2928        });
 2929        self.update_restoration_data(cx, |data| {
 2930            data.folds = inmemory_folds;
 2931        });
 2932
 2933        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2934            return;
 2935        };
 2936        let background_executor = cx.background_executor().clone();
 2937        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2938        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2939            display_map
 2940                .snapshot(cx)
 2941                .folds_in_range(0..snapshot.len())
 2942                .map(|fold| {
 2943                    (
 2944                        fold.range.start.text_anchor.to_offset(&snapshot),
 2945                        fold.range.end.text_anchor.to_offset(&snapshot),
 2946                    )
 2947                })
 2948                .collect()
 2949        });
 2950        self.serialize_folds = cx.background_spawn(async move {
 2951            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2952            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2953                .await
 2954                .with_context(|| {
 2955                    format!(
 2956                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2957                    )
 2958                })
 2959                .log_err();
 2960        });
 2961    }
 2962
 2963    pub fn sync_selections(
 2964        &mut self,
 2965        other: Entity<Editor>,
 2966        cx: &mut Context<Self>,
 2967    ) -> gpui::Subscription {
 2968        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2969        self.selections.change_with(cx, |selections| {
 2970            selections.select_anchors(other_selections);
 2971        });
 2972
 2973        let other_subscription =
 2974            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2975                EditorEvent::SelectionsChanged { local: true } => {
 2976                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2977                    if other_selections.is_empty() {
 2978                        return;
 2979                    }
 2980                    this.selections.change_with(cx, |selections| {
 2981                        selections.select_anchors(other_selections);
 2982                    });
 2983                }
 2984                _ => {}
 2985            });
 2986
 2987        let this_subscription =
 2988            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2989                EditorEvent::SelectionsChanged { local: true } => {
 2990                    let these_selections = this.selections.disjoint.to_vec();
 2991                    if these_selections.is_empty() {
 2992                        return;
 2993                    }
 2994                    other.update(cx, |other_editor, cx| {
 2995                        other_editor.selections.change_with(cx, |selections| {
 2996                            selections.select_anchors(these_selections);
 2997                        })
 2998                    });
 2999                }
 3000                _ => {}
 3001            });
 3002
 3003        Subscription::join(other_subscription, this_subscription)
 3004    }
 3005
 3006    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3007    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3008    /// effects of selection change occur at the end of the transaction.
 3009    pub fn change_selections<R>(
 3010        &mut self,
 3011        autoscroll: Option<Autoscroll>,
 3012        window: &mut Window,
 3013        cx: &mut Context<Self>,
 3014        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3015    ) -> R {
 3016        self.change_selections_inner(true, autoscroll, window, cx, change)
 3017    }
 3018
 3019    pub(crate) fn change_selections_without_updating_completions<R>(
 3020        &mut self,
 3021        autoscroll: Option<Autoscroll>,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3025    ) -> R {
 3026        self.change_selections_inner(false, autoscroll, window, cx, change)
 3027    }
 3028
 3029    fn change_selections_inner<R>(
 3030        &mut self,
 3031        should_update_completions: bool,
 3032        autoscroll: Option<Autoscroll>,
 3033        window: &mut Window,
 3034        cx: &mut Context<Self>,
 3035        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3036    ) -> R {
 3037        if let Some(state) = &mut self.deferred_selection_effects_state {
 3038            state.autoscroll = autoscroll.or(state.autoscroll);
 3039            state.should_update_completions = should_update_completions;
 3040            let (changed, result) = self.selections.change_with(cx, change);
 3041            state.changed |= changed;
 3042            return result;
 3043        }
 3044        let mut state = DeferredSelectionEffectsState {
 3045            changed: false,
 3046            should_update_completions,
 3047            autoscroll,
 3048            old_cursor_position: self.selections.newest_anchor().head(),
 3049            history_entry: SelectionHistoryEntry {
 3050                selections: self.selections.disjoint_anchors(),
 3051                select_next_state: self.select_next_state.clone(),
 3052                select_prev_state: self.select_prev_state.clone(),
 3053                add_selections_state: self.add_selections_state.clone(),
 3054            },
 3055        };
 3056        let (changed, result) = self.selections.change_with(cx, change);
 3057        state.changed = state.changed || changed;
 3058        if self.defer_selection_effects {
 3059            self.deferred_selection_effects_state = Some(state);
 3060        } else {
 3061            self.apply_selection_effects(state, window, cx);
 3062        }
 3063        result
 3064    }
 3065
 3066    /// Defers the effects of selection change, so that the effects of multiple calls to
 3067    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3068    /// to selection history and the state of popovers based on selection position aren't
 3069    /// erroneously updated.
 3070    pub fn with_selection_effects_deferred<R>(
 3071        &mut self,
 3072        window: &mut Window,
 3073        cx: &mut Context<Self>,
 3074        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3075    ) -> R {
 3076        let already_deferred = self.defer_selection_effects;
 3077        self.defer_selection_effects = true;
 3078        let result = update(self, window, cx);
 3079        if !already_deferred {
 3080            self.defer_selection_effects = false;
 3081            if let Some(state) = self.deferred_selection_effects_state.take() {
 3082                self.apply_selection_effects(state, window, cx);
 3083            }
 3084        }
 3085        result
 3086    }
 3087
 3088    fn apply_selection_effects(
 3089        &mut self,
 3090        state: DeferredSelectionEffectsState,
 3091        window: &mut Window,
 3092        cx: &mut Context<Self>,
 3093    ) {
 3094        if state.changed {
 3095            self.selection_history.push(state.history_entry);
 3096
 3097            if let Some(autoscroll) = state.autoscroll {
 3098                self.request_autoscroll(autoscroll, cx);
 3099            }
 3100
 3101            let old_cursor_position = &state.old_cursor_position;
 3102
 3103            self.selections_did_change(
 3104                true,
 3105                &old_cursor_position,
 3106                state.should_update_completions,
 3107                window,
 3108                cx,
 3109            );
 3110
 3111            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3112                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3113            }
 3114        }
 3115    }
 3116
 3117    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3118    where
 3119        I: IntoIterator<Item = (Range<S>, T)>,
 3120        S: ToOffset,
 3121        T: Into<Arc<str>>,
 3122    {
 3123        if self.read_only(cx) {
 3124            return;
 3125        }
 3126
 3127        self.buffer
 3128            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3129    }
 3130
 3131    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3132    where
 3133        I: IntoIterator<Item = (Range<S>, T)>,
 3134        S: ToOffset,
 3135        T: Into<Arc<str>>,
 3136    {
 3137        if self.read_only(cx) {
 3138            return;
 3139        }
 3140
 3141        self.buffer.update(cx, |buffer, cx| {
 3142            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3143        });
 3144    }
 3145
 3146    pub fn edit_with_block_indent<I, S, T>(
 3147        &mut self,
 3148        edits: I,
 3149        original_indent_columns: Vec<Option<u32>>,
 3150        cx: &mut Context<Self>,
 3151    ) where
 3152        I: IntoIterator<Item = (Range<S>, T)>,
 3153        S: ToOffset,
 3154        T: Into<Arc<str>>,
 3155    {
 3156        if self.read_only(cx) {
 3157            return;
 3158        }
 3159
 3160        self.buffer.update(cx, |buffer, cx| {
 3161            buffer.edit(
 3162                edits,
 3163                Some(AutoindentMode::Block {
 3164                    original_indent_columns,
 3165                }),
 3166                cx,
 3167            )
 3168        });
 3169    }
 3170
 3171    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3172        self.hide_context_menu(window, cx);
 3173
 3174        match phase {
 3175            SelectPhase::Begin {
 3176                position,
 3177                add,
 3178                click_count,
 3179            } => self.begin_selection(position, add, click_count, window, cx),
 3180            SelectPhase::BeginColumnar {
 3181                position,
 3182                goal_column,
 3183                reset,
 3184            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3185            SelectPhase::Extend {
 3186                position,
 3187                click_count,
 3188            } => self.extend_selection(position, click_count, window, cx),
 3189            SelectPhase::Update {
 3190                position,
 3191                goal_column,
 3192                scroll_delta,
 3193            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3194            SelectPhase::End => self.end_selection(window, cx),
 3195        }
 3196    }
 3197
 3198    fn extend_selection(
 3199        &mut self,
 3200        position: DisplayPoint,
 3201        click_count: usize,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3206        let tail = self.selections.newest::<usize>(cx).tail();
 3207        self.begin_selection(position, false, click_count, window, cx);
 3208
 3209        let position = position.to_offset(&display_map, Bias::Left);
 3210        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3211
 3212        let mut pending_selection = self
 3213            .selections
 3214            .pending_anchor()
 3215            .expect("extend_selection not called with pending selection");
 3216        if position >= tail {
 3217            pending_selection.start = tail_anchor;
 3218        } else {
 3219            pending_selection.end = tail_anchor;
 3220            pending_selection.reversed = true;
 3221        }
 3222
 3223        let mut pending_mode = self.selections.pending_mode().unwrap();
 3224        match &mut pending_mode {
 3225            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3226            _ => {}
 3227        }
 3228
 3229        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3230
 3231        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3232            s.set_pending(pending_selection, pending_mode)
 3233        });
 3234    }
 3235
 3236    fn begin_selection(
 3237        &mut self,
 3238        position: DisplayPoint,
 3239        add: bool,
 3240        click_count: usize,
 3241        window: &mut Window,
 3242        cx: &mut Context<Self>,
 3243    ) {
 3244        if !self.focus_handle.is_focused(window) {
 3245            self.last_focused_descendant = None;
 3246            window.focus(&self.focus_handle);
 3247        }
 3248
 3249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3250        let buffer = &display_map.buffer_snapshot;
 3251        let position = display_map.clip_point(position, Bias::Left);
 3252
 3253        let start;
 3254        let end;
 3255        let mode;
 3256        let mut auto_scroll;
 3257        match click_count {
 3258            1 => {
 3259                start = buffer.anchor_before(position.to_point(&display_map));
 3260                end = start;
 3261                mode = SelectMode::Character;
 3262                auto_scroll = true;
 3263            }
 3264            2 => {
 3265                let range = movement::surrounding_word(&display_map, position);
 3266                start = buffer.anchor_before(range.start.to_point(&display_map));
 3267                end = buffer.anchor_before(range.end.to_point(&display_map));
 3268                mode = SelectMode::Word(start..end);
 3269                auto_scroll = true;
 3270            }
 3271            3 => {
 3272                let position = display_map
 3273                    .clip_point(position, Bias::Left)
 3274                    .to_point(&display_map);
 3275                let line_start = display_map.prev_line_boundary(position).0;
 3276                let next_line_start = buffer.clip_point(
 3277                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3278                    Bias::Left,
 3279                );
 3280                start = buffer.anchor_before(line_start);
 3281                end = buffer.anchor_before(next_line_start);
 3282                mode = SelectMode::Line(start..end);
 3283                auto_scroll = true;
 3284            }
 3285            _ => {
 3286                start = buffer.anchor_before(0);
 3287                end = buffer.anchor_before(buffer.len());
 3288                mode = SelectMode::All;
 3289                auto_scroll = false;
 3290            }
 3291        }
 3292        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3293
 3294        let point_to_delete: Option<usize> = {
 3295            let selected_points: Vec<Selection<Point>> =
 3296                self.selections.disjoint_in_range(start..end, cx);
 3297
 3298            if !add || click_count > 1 {
 3299                None
 3300            } else if !selected_points.is_empty() {
 3301                Some(selected_points[0].id)
 3302            } else {
 3303                let clicked_point_already_selected =
 3304                    self.selections.disjoint.iter().find(|selection| {
 3305                        selection.start.to_point(buffer) == start.to_point(buffer)
 3306                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3307                    });
 3308
 3309                clicked_point_already_selected.map(|selection| selection.id)
 3310            }
 3311        };
 3312
 3313        let selections_count = self.selections.count();
 3314
 3315        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3316            if let Some(point_to_delete) = point_to_delete {
 3317                s.delete(point_to_delete);
 3318
 3319                if selections_count == 1 {
 3320                    s.set_pending_anchor_range(start..end, mode);
 3321                }
 3322            } else {
 3323                if !add {
 3324                    s.clear_disjoint();
 3325                }
 3326
 3327                s.set_pending_anchor_range(start..end, mode);
 3328            }
 3329        });
 3330    }
 3331
 3332    fn begin_columnar_selection(
 3333        &mut self,
 3334        position: DisplayPoint,
 3335        goal_column: u32,
 3336        reset: bool,
 3337        window: &mut Window,
 3338        cx: &mut Context<Self>,
 3339    ) {
 3340        if !self.focus_handle.is_focused(window) {
 3341            self.last_focused_descendant = None;
 3342            window.focus(&self.focus_handle);
 3343        }
 3344
 3345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3346
 3347        if reset {
 3348            let pointer_position = display_map
 3349                .buffer_snapshot
 3350                .anchor_before(position.to_point(&display_map));
 3351
 3352            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3353                s.clear_disjoint();
 3354                s.set_pending_anchor_range(
 3355                    pointer_position..pointer_position,
 3356                    SelectMode::Character,
 3357                );
 3358            });
 3359            if position.column() != goal_column {
 3360                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3361            } else {
 3362                self.columnar_display_point = None;
 3363            }
 3364        }
 3365
 3366        let tail = self.selections.newest::<Point>(cx).tail();
 3367        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3368
 3369        if !reset {
 3370            self.columnar_display_point = None;
 3371            self.select_columns(
 3372                tail.to_display_point(&display_map),
 3373                position,
 3374                goal_column,
 3375                &display_map,
 3376                window,
 3377                cx,
 3378            );
 3379        }
 3380    }
 3381
 3382    fn update_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        goal_column: u32,
 3386        scroll_delta: gpui::Point<f32>,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389    ) {
 3390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3391
 3392        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3393            let tail = self
 3394                .columnar_display_point
 3395                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3396            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3397        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3398            let buffer = self.buffer.read(cx).snapshot(cx);
 3399            let head;
 3400            let tail;
 3401            let mode = self.selections.pending_mode().unwrap();
 3402            match &mode {
 3403                SelectMode::Character => {
 3404                    head = position.to_point(&display_map);
 3405                    tail = pending.tail().to_point(&buffer);
 3406                }
 3407                SelectMode::Word(original_range) => {
 3408                    let original_display_range = original_range.start.to_display_point(&display_map)
 3409                        ..original_range.end.to_display_point(&display_map);
 3410                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3411                        ..original_display_range.end.to_point(&display_map);
 3412                    if movement::is_inside_word(&display_map, position)
 3413                        || original_display_range.contains(&position)
 3414                    {
 3415                        let word_range = movement::surrounding_word(&display_map, position);
 3416                        if word_range.start < original_display_range.start {
 3417                            head = word_range.start.to_point(&display_map);
 3418                        } else {
 3419                            head = word_range.end.to_point(&display_map);
 3420                        }
 3421                    } else {
 3422                        head = position.to_point(&display_map);
 3423                    }
 3424
 3425                    if head <= original_buffer_range.start {
 3426                        tail = original_buffer_range.end;
 3427                    } else {
 3428                        tail = original_buffer_range.start;
 3429                    }
 3430                }
 3431                SelectMode::Line(original_range) => {
 3432                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3433
 3434                    let position = display_map
 3435                        .clip_point(position, Bias::Left)
 3436                        .to_point(&display_map);
 3437                    let line_start = display_map.prev_line_boundary(position).0;
 3438                    let next_line_start = buffer.clip_point(
 3439                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3440                        Bias::Left,
 3441                    );
 3442
 3443                    if line_start < original_range.start {
 3444                        head = line_start
 3445                    } else {
 3446                        head = next_line_start
 3447                    }
 3448
 3449                    if head <= original_range.start {
 3450                        tail = original_range.end;
 3451                    } else {
 3452                        tail = original_range.start;
 3453                    }
 3454                }
 3455                SelectMode::All => {
 3456                    return;
 3457                }
 3458            };
 3459
 3460            if head < tail {
 3461                pending.start = buffer.anchor_before(head);
 3462                pending.end = buffer.anchor_before(tail);
 3463                pending.reversed = true;
 3464            } else {
 3465                pending.start = buffer.anchor_before(tail);
 3466                pending.end = buffer.anchor_before(head);
 3467                pending.reversed = false;
 3468            }
 3469
 3470            self.change_selections(None, window, cx, |s| {
 3471                s.set_pending(pending, mode);
 3472            });
 3473        } else {
 3474            log::error!("update_selection dispatched with no pending selection");
 3475            return;
 3476        }
 3477
 3478        self.apply_scroll_delta(scroll_delta, window, cx);
 3479        cx.notify();
 3480    }
 3481
 3482    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3483        self.columnar_selection_tail.take();
 3484        if self.selections.pending_anchor().is_some() {
 3485            let selections = self.selections.all::<usize>(cx);
 3486            self.change_selections(None, window, cx, |s| {
 3487                s.select(selections);
 3488                s.clear_pending();
 3489            });
 3490        }
 3491    }
 3492
 3493    fn select_columns(
 3494        &mut self,
 3495        tail: DisplayPoint,
 3496        head: DisplayPoint,
 3497        goal_column: u32,
 3498        display_map: &DisplaySnapshot,
 3499        window: &mut Window,
 3500        cx: &mut Context<Self>,
 3501    ) {
 3502        let start_row = cmp::min(tail.row(), head.row());
 3503        let end_row = cmp::max(tail.row(), head.row());
 3504        let start_column = cmp::min(tail.column(), goal_column);
 3505        let end_column = cmp::max(tail.column(), goal_column);
 3506        let reversed = start_column < tail.column();
 3507
 3508        let selection_ranges = (start_row.0..=end_row.0)
 3509            .map(DisplayRow)
 3510            .filter_map(|row| {
 3511                if !display_map.is_block_line(row) {
 3512                    let start = display_map
 3513                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3514                        .to_point(display_map);
 3515                    let end = display_map
 3516                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3517                        .to_point(display_map);
 3518                    if reversed {
 3519                        Some(end..start)
 3520                    } else {
 3521                        Some(start..end)
 3522                    }
 3523                } else {
 3524                    None
 3525                }
 3526            })
 3527            .collect::<Vec<_>>();
 3528
 3529        let mut non_empty_ranges = selection_ranges
 3530            .iter()
 3531            .filter(|selection_range| selection_range.start != selection_range.end)
 3532            .peekable();
 3533
 3534        let ranges = if non_empty_ranges.peek().is_some() {
 3535            non_empty_ranges.cloned().collect()
 3536        } else {
 3537            selection_ranges
 3538        };
 3539
 3540        self.change_selections(None, window, cx, |s| {
 3541            s.select_ranges(ranges);
 3542        });
 3543        cx.notify();
 3544    }
 3545
 3546    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3547        self.selections
 3548            .all_adjusted(cx)
 3549            .iter()
 3550            .any(|selection| !selection.is_empty())
 3551    }
 3552
 3553    pub fn has_pending_nonempty_selection(&self) -> bool {
 3554        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3555            Some(Selection { start, end, .. }) => start != end,
 3556            None => false,
 3557        };
 3558
 3559        pending_nonempty_selection
 3560            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3561    }
 3562
 3563    pub fn has_pending_selection(&self) -> bool {
 3564        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3565    }
 3566
 3567    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3568        self.selection_mark_mode = false;
 3569        self.selection_drag_state = SelectionDragState::None;
 3570
 3571        if self.clear_expanded_diff_hunks(cx) {
 3572            cx.notify();
 3573            return;
 3574        }
 3575        if self.dismiss_menus_and_popups(true, window, cx) {
 3576            return;
 3577        }
 3578
 3579        if self.mode.is_full()
 3580            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3581        {
 3582            return;
 3583        }
 3584
 3585        cx.propagate();
 3586    }
 3587
 3588    pub fn dismiss_menus_and_popups(
 3589        &mut self,
 3590        is_user_requested: bool,
 3591        window: &mut Window,
 3592        cx: &mut Context<Self>,
 3593    ) -> bool {
 3594        if self.take_rename(false, window, cx).is_some() {
 3595            return true;
 3596        }
 3597
 3598        if hide_hover(self, cx) {
 3599            return true;
 3600        }
 3601
 3602        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3603            return true;
 3604        }
 3605
 3606        if self.hide_context_menu(window, cx).is_some() {
 3607            return true;
 3608        }
 3609
 3610        if self.mouse_context_menu.take().is_some() {
 3611            return true;
 3612        }
 3613
 3614        if is_user_requested && self.discard_inline_completion(true, cx) {
 3615            return true;
 3616        }
 3617
 3618        if self.snippet_stack.pop().is_some() {
 3619            return true;
 3620        }
 3621
 3622        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3623            self.dismiss_diagnostics(cx);
 3624            return true;
 3625        }
 3626
 3627        false
 3628    }
 3629
 3630    fn linked_editing_ranges_for(
 3631        &self,
 3632        selection: Range<text::Anchor>,
 3633        cx: &App,
 3634    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3635        if self.linked_edit_ranges.is_empty() {
 3636            return None;
 3637        }
 3638        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3639            selection.end.buffer_id.and_then(|end_buffer_id| {
 3640                if selection.start.buffer_id != Some(end_buffer_id) {
 3641                    return None;
 3642                }
 3643                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3644                let snapshot = buffer.read(cx).snapshot();
 3645                self.linked_edit_ranges
 3646                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3647                    .map(|ranges| (ranges, snapshot, buffer))
 3648            })?;
 3649        use text::ToOffset as TO;
 3650        // find offset from the start of current range to current cursor position
 3651        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3652
 3653        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3654        let start_difference = start_offset - start_byte_offset;
 3655        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3656        let end_difference = end_offset - start_byte_offset;
 3657        // Current range has associated linked ranges.
 3658        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3659        for range in linked_ranges.iter() {
 3660            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3661            let end_offset = start_offset + end_difference;
 3662            let start_offset = start_offset + start_difference;
 3663            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3664                continue;
 3665            }
 3666            if self.selections.disjoint_anchor_ranges().any(|s| {
 3667                if s.start.buffer_id != selection.start.buffer_id
 3668                    || s.end.buffer_id != selection.end.buffer_id
 3669                {
 3670                    return false;
 3671                }
 3672                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3673                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3674            }) {
 3675                continue;
 3676            }
 3677            let start = buffer_snapshot.anchor_after(start_offset);
 3678            let end = buffer_snapshot.anchor_after(end_offset);
 3679            linked_edits
 3680                .entry(buffer.clone())
 3681                .or_default()
 3682                .push(start..end);
 3683        }
 3684        Some(linked_edits)
 3685    }
 3686
 3687    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3688        let text: Arc<str> = text.into();
 3689
 3690        if self.read_only(cx) {
 3691            return;
 3692        }
 3693
 3694        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3695
 3696        let selections = self.selections.all_adjusted(cx);
 3697        let mut bracket_inserted = false;
 3698        let mut edits = Vec::new();
 3699        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3700        let mut new_selections = Vec::with_capacity(selections.len());
 3701        let mut new_autoclose_regions = Vec::new();
 3702        let snapshot = self.buffer.read(cx).read(cx);
 3703        let mut clear_linked_edit_ranges = false;
 3704
 3705        for (selection, autoclose_region) in
 3706            self.selections_with_autoclose_regions(selections, &snapshot)
 3707        {
 3708            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3709                // Determine if the inserted text matches the opening or closing
 3710                // bracket of any of this language's bracket pairs.
 3711                let mut bracket_pair = None;
 3712                let mut is_bracket_pair_start = false;
 3713                let mut is_bracket_pair_end = false;
 3714                if !text.is_empty() {
 3715                    let mut bracket_pair_matching_end = None;
 3716                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3717                    //  and they are removing the character that triggered IME popup.
 3718                    for (pair, enabled) in scope.brackets() {
 3719                        if !pair.close && !pair.surround {
 3720                            continue;
 3721                        }
 3722
 3723                        if enabled && pair.start.ends_with(text.as_ref()) {
 3724                            let prefix_len = pair.start.len() - text.len();
 3725                            let preceding_text_matches_prefix = prefix_len == 0
 3726                                || (selection.start.column >= (prefix_len as u32)
 3727                                    && snapshot.contains_str_at(
 3728                                        Point::new(
 3729                                            selection.start.row,
 3730                                            selection.start.column - (prefix_len as u32),
 3731                                        ),
 3732                                        &pair.start[..prefix_len],
 3733                                    ));
 3734                            if preceding_text_matches_prefix {
 3735                                bracket_pair = Some(pair.clone());
 3736                                is_bracket_pair_start = true;
 3737                                break;
 3738                            }
 3739                        }
 3740                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3741                        {
 3742                            // take first bracket pair matching end, but don't break in case a later bracket
 3743                            // pair matches start
 3744                            bracket_pair_matching_end = Some(pair.clone());
 3745                        }
 3746                    }
 3747                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3748                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3749                        is_bracket_pair_end = true;
 3750                    }
 3751                }
 3752
 3753                if let Some(bracket_pair) = bracket_pair {
 3754                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3755                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3756                    let auto_surround =
 3757                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3758                    if selection.is_empty() {
 3759                        if is_bracket_pair_start {
 3760                            // If the inserted text is a suffix of an opening bracket and the
 3761                            // selection is preceded by the rest of the opening bracket, then
 3762                            // insert the closing bracket.
 3763                            let following_text_allows_autoclose = snapshot
 3764                                .chars_at(selection.start)
 3765                                .next()
 3766                                .map_or(true, |c| scope.should_autoclose_before(c));
 3767
 3768                            let preceding_text_allows_autoclose = selection.start.column == 0
 3769                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3770                                    true,
 3771                                    |c| {
 3772                                        bracket_pair.start != bracket_pair.end
 3773                                            || !snapshot
 3774                                                .char_classifier_at(selection.start)
 3775                                                .is_word(c)
 3776                                    },
 3777                                );
 3778
 3779                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3780                                && bracket_pair.start.len() == 1
 3781                            {
 3782                                let target = bracket_pair.start.chars().next().unwrap();
 3783                                let current_line_count = snapshot
 3784                                    .reversed_chars_at(selection.start)
 3785                                    .take_while(|&c| c != '\n')
 3786                                    .filter(|&c| c == target)
 3787                                    .count();
 3788                                current_line_count % 2 == 1
 3789                            } else {
 3790                                false
 3791                            };
 3792
 3793                            if autoclose
 3794                                && bracket_pair.close
 3795                                && following_text_allows_autoclose
 3796                                && preceding_text_allows_autoclose
 3797                                && !is_closing_quote
 3798                            {
 3799                                let anchor = snapshot.anchor_before(selection.end);
 3800                                new_selections.push((selection.map(|_| anchor), text.len()));
 3801                                new_autoclose_regions.push((
 3802                                    anchor,
 3803                                    text.len(),
 3804                                    selection.id,
 3805                                    bracket_pair.clone(),
 3806                                ));
 3807                                edits.push((
 3808                                    selection.range(),
 3809                                    format!("{}{}", text, bracket_pair.end).into(),
 3810                                ));
 3811                                bracket_inserted = true;
 3812                                continue;
 3813                            }
 3814                        }
 3815
 3816                        if let Some(region) = autoclose_region {
 3817                            // If the selection is followed by an auto-inserted closing bracket,
 3818                            // then don't insert that closing bracket again; just move the selection
 3819                            // past the closing bracket.
 3820                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3821                                && text.as_ref() == region.pair.end.as_str();
 3822                            if should_skip {
 3823                                let anchor = snapshot.anchor_after(selection.end);
 3824                                new_selections
 3825                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3826                                continue;
 3827                            }
 3828                        }
 3829
 3830                        let always_treat_brackets_as_autoclosed = snapshot
 3831                            .language_settings_at(selection.start, cx)
 3832                            .always_treat_brackets_as_autoclosed;
 3833                        if always_treat_brackets_as_autoclosed
 3834                            && is_bracket_pair_end
 3835                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3836                        {
 3837                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3838                            // and the inserted text is a closing bracket and the selection is followed
 3839                            // by the closing bracket then move the selection past the closing bracket.
 3840                            let anchor = snapshot.anchor_after(selection.end);
 3841                            new_selections.push((selection.map(|_| anchor), text.len()));
 3842                            continue;
 3843                        }
 3844                    }
 3845                    // If an opening bracket is 1 character long and is typed while
 3846                    // text is selected, then surround that text with the bracket pair.
 3847                    else if auto_surround
 3848                        && bracket_pair.surround
 3849                        && is_bracket_pair_start
 3850                        && bracket_pair.start.chars().count() == 1
 3851                    {
 3852                        edits.push((selection.start..selection.start, text.clone()));
 3853                        edits.push((
 3854                            selection.end..selection.end,
 3855                            bracket_pair.end.as_str().into(),
 3856                        ));
 3857                        bracket_inserted = true;
 3858                        new_selections.push((
 3859                            Selection {
 3860                                id: selection.id,
 3861                                start: snapshot.anchor_after(selection.start),
 3862                                end: snapshot.anchor_before(selection.end),
 3863                                reversed: selection.reversed,
 3864                                goal: selection.goal,
 3865                            },
 3866                            0,
 3867                        ));
 3868                        continue;
 3869                    }
 3870                }
 3871            }
 3872
 3873            if self.auto_replace_emoji_shortcode
 3874                && selection.is_empty()
 3875                && text.as_ref().ends_with(':')
 3876            {
 3877                if let Some(possible_emoji_short_code) =
 3878                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3879                {
 3880                    if !possible_emoji_short_code.is_empty() {
 3881                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3882                            let emoji_shortcode_start = Point::new(
 3883                                selection.start.row,
 3884                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3885                            );
 3886
 3887                            // Remove shortcode from buffer
 3888                            edits.push((
 3889                                emoji_shortcode_start..selection.start,
 3890                                "".to_string().into(),
 3891                            ));
 3892                            new_selections.push((
 3893                                Selection {
 3894                                    id: selection.id,
 3895                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3896                                    end: snapshot.anchor_before(selection.start),
 3897                                    reversed: selection.reversed,
 3898                                    goal: selection.goal,
 3899                                },
 3900                                0,
 3901                            ));
 3902
 3903                            // Insert emoji
 3904                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3905                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3906                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3907
 3908                            continue;
 3909                        }
 3910                    }
 3911                }
 3912            }
 3913
 3914            // If not handling any auto-close operation, then just replace the selected
 3915            // text with the given input and move the selection to the end of the
 3916            // newly inserted text.
 3917            let anchor = snapshot.anchor_after(selection.end);
 3918            if !self.linked_edit_ranges.is_empty() {
 3919                let start_anchor = snapshot.anchor_before(selection.start);
 3920
 3921                let is_word_char = text.chars().next().map_or(true, |char| {
 3922                    let classifier = snapshot
 3923                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3924                        .ignore_punctuation(true);
 3925                    classifier.is_word(char)
 3926                });
 3927
 3928                if is_word_char {
 3929                    if let Some(ranges) = self
 3930                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3931                    {
 3932                        for (buffer, edits) in ranges {
 3933                            linked_edits
 3934                                .entry(buffer.clone())
 3935                                .or_default()
 3936                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3937                        }
 3938                    }
 3939                } else {
 3940                    clear_linked_edit_ranges = true;
 3941                }
 3942            }
 3943
 3944            new_selections.push((selection.map(|_| anchor), 0));
 3945            edits.push((selection.start..selection.end, text.clone()));
 3946        }
 3947
 3948        drop(snapshot);
 3949
 3950        self.transact(window, cx, |this, window, cx| {
 3951            if clear_linked_edit_ranges {
 3952                this.linked_edit_ranges.clear();
 3953            }
 3954            let initial_buffer_versions =
 3955                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3956
 3957            this.buffer.update(cx, |buffer, cx| {
 3958                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3959            });
 3960            for (buffer, edits) in linked_edits {
 3961                buffer.update(cx, |buffer, cx| {
 3962                    let snapshot = buffer.snapshot();
 3963                    let edits = edits
 3964                        .into_iter()
 3965                        .map(|(range, text)| {
 3966                            use text::ToPoint as TP;
 3967                            let end_point = TP::to_point(&range.end, &snapshot);
 3968                            let start_point = TP::to_point(&range.start, &snapshot);
 3969                            (start_point..end_point, text)
 3970                        })
 3971                        .sorted_by_key(|(range, _)| range.start);
 3972                    buffer.edit(edits, None, cx);
 3973                })
 3974            }
 3975            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3976            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3977            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3978            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3979                .zip(new_selection_deltas)
 3980                .map(|(selection, delta)| Selection {
 3981                    id: selection.id,
 3982                    start: selection.start + delta,
 3983                    end: selection.end + delta,
 3984                    reversed: selection.reversed,
 3985                    goal: SelectionGoal::None,
 3986                })
 3987                .collect::<Vec<_>>();
 3988
 3989            let mut i = 0;
 3990            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3991                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3992                let start = map.buffer_snapshot.anchor_before(position);
 3993                let end = map.buffer_snapshot.anchor_after(position);
 3994                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3995                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3996                        Ordering::Less => i += 1,
 3997                        Ordering::Greater => break,
 3998                        Ordering::Equal => {
 3999                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4000                                Ordering::Less => i += 1,
 4001                                Ordering::Equal => break,
 4002                                Ordering::Greater => break,
 4003                            }
 4004                        }
 4005                    }
 4006                }
 4007                this.autoclose_regions.insert(
 4008                    i,
 4009                    AutocloseRegion {
 4010                        selection_id,
 4011                        range: start..end,
 4012                        pair,
 4013                    },
 4014                );
 4015            }
 4016
 4017            let had_active_inline_completion = this.has_active_inline_completion();
 4018            this.change_selections_without_updating_completions(
 4019                Some(Autoscroll::fit()),
 4020                window,
 4021                cx,
 4022                |s| s.select(new_selections),
 4023            );
 4024
 4025            if !bracket_inserted {
 4026                if let Some(on_type_format_task) =
 4027                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4028                {
 4029                    on_type_format_task.detach_and_log_err(cx);
 4030                }
 4031            }
 4032
 4033            let editor_settings = EditorSettings::get_global(cx);
 4034            if bracket_inserted
 4035                && (editor_settings.auto_signature_help
 4036                    || editor_settings.show_signature_help_after_edits)
 4037            {
 4038                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4039            }
 4040
 4041            let trigger_in_words =
 4042                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4043            if this.hard_wrap.is_some() {
 4044                let latest: Range<Point> = this.selections.newest(cx).range();
 4045                if latest.is_empty()
 4046                    && this
 4047                        .buffer()
 4048                        .read(cx)
 4049                        .snapshot(cx)
 4050                        .line_len(MultiBufferRow(latest.start.row))
 4051                        == latest.start.column
 4052                {
 4053                    this.rewrap_impl(
 4054                        RewrapOptions {
 4055                            override_language_settings: true,
 4056                            preserve_existing_whitespace: true,
 4057                        },
 4058                        cx,
 4059                    )
 4060                }
 4061            }
 4062            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4063            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4064            this.refresh_inline_completion(true, false, window, cx);
 4065            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4066        });
 4067    }
 4068
 4069    fn find_possible_emoji_shortcode_at_position(
 4070        snapshot: &MultiBufferSnapshot,
 4071        position: Point,
 4072    ) -> Option<String> {
 4073        let mut chars = Vec::new();
 4074        let mut found_colon = false;
 4075        for char in snapshot.reversed_chars_at(position).take(100) {
 4076            // Found a possible emoji shortcode in the middle of the buffer
 4077            if found_colon {
 4078                if char.is_whitespace() {
 4079                    chars.reverse();
 4080                    return Some(chars.iter().collect());
 4081                }
 4082                // If the previous character is not a whitespace, we are in the middle of a word
 4083                // and we only want to complete the shortcode if the word is made up of other emojis
 4084                let mut containing_word = String::new();
 4085                for ch in snapshot
 4086                    .reversed_chars_at(position)
 4087                    .skip(chars.len() + 1)
 4088                    .take(100)
 4089                {
 4090                    if ch.is_whitespace() {
 4091                        break;
 4092                    }
 4093                    containing_word.push(ch);
 4094                }
 4095                let containing_word = containing_word.chars().rev().collect::<String>();
 4096                if util::word_consists_of_emojis(containing_word.as_str()) {
 4097                    chars.reverse();
 4098                    return Some(chars.iter().collect());
 4099                }
 4100            }
 4101
 4102            if char.is_whitespace() || !char.is_ascii() {
 4103                return None;
 4104            }
 4105            if char == ':' {
 4106                found_colon = true;
 4107            } else {
 4108                chars.push(char);
 4109            }
 4110        }
 4111        // Found a possible emoji shortcode at the beginning of the buffer
 4112        chars.reverse();
 4113        Some(chars.iter().collect())
 4114    }
 4115
 4116    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4117        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4118        self.transact(window, cx, |this, window, cx| {
 4119            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4120                let selections = this.selections.all::<usize>(cx);
 4121                let multi_buffer = this.buffer.read(cx);
 4122                let buffer = multi_buffer.snapshot(cx);
 4123                selections
 4124                    .iter()
 4125                    .map(|selection| {
 4126                        let start_point = selection.start.to_point(&buffer);
 4127                        let mut existing_indent =
 4128                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4129                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4130                        let start = selection.start;
 4131                        let end = selection.end;
 4132                        let selection_is_empty = start == end;
 4133                        let language_scope = buffer.language_scope_at(start);
 4134                        let (
 4135                            comment_delimiter,
 4136                            doc_delimiter,
 4137                            insert_extra_newline,
 4138                            indent_on_newline,
 4139                            indent_on_extra_newline,
 4140                        ) = if let Some(language) = &language_scope {
 4141                            let mut insert_extra_newline =
 4142                                insert_extra_newline_brackets(&buffer, start..end, language)
 4143                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4144
 4145                            // Comment extension on newline is allowed only for cursor selections
 4146                            let comment_delimiter = maybe!({
 4147                                if !selection_is_empty {
 4148                                    return None;
 4149                                }
 4150
 4151                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4152                                    return None;
 4153                                }
 4154
 4155                                let delimiters = language.line_comment_prefixes();
 4156                                let max_len_of_delimiter =
 4157                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4158                                let (snapshot, range) =
 4159                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4160
 4161                                let num_of_whitespaces = snapshot
 4162                                    .chars_for_range(range.clone())
 4163                                    .take_while(|c| c.is_whitespace())
 4164                                    .count();
 4165                                let comment_candidate = snapshot
 4166                                    .chars_for_range(range)
 4167                                    .skip(num_of_whitespaces)
 4168                                    .take(max_len_of_delimiter)
 4169                                    .collect::<String>();
 4170                                let (delimiter, trimmed_len) = delimiters
 4171                                    .iter()
 4172                                    .filter_map(|delimiter| {
 4173                                        let prefix = delimiter.trim_end();
 4174                                        if comment_candidate.starts_with(prefix) {
 4175                                            Some((delimiter, prefix.len()))
 4176                                        } else {
 4177                                            None
 4178                                        }
 4179                                    })
 4180                                    .max_by_key(|(_, len)| *len)?;
 4181
 4182                                let cursor_is_placed_after_comment_marker =
 4183                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4184                                if cursor_is_placed_after_comment_marker {
 4185                                    Some(delimiter.clone())
 4186                                } else {
 4187                                    None
 4188                                }
 4189                            });
 4190
 4191                            let mut indent_on_newline = IndentSize::spaces(0);
 4192                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4193
 4194                            let doc_delimiter = maybe!({
 4195                                if !selection_is_empty {
 4196                                    return None;
 4197                                }
 4198
 4199                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4200                                    return None;
 4201                                }
 4202
 4203                                let DocumentationConfig {
 4204                                    start: start_tag,
 4205                                    end: end_tag,
 4206                                    prefix: delimiter,
 4207                                    tab_size: len,
 4208                                } = language.documentation()?;
 4209
 4210                                let is_within_block_comment = buffer
 4211                                    .language_scope_at(start_point)
 4212                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4213                                if !is_within_block_comment {
 4214                                    return None;
 4215                                }
 4216
 4217                                let (snapshot, range) =
 4218                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4219
 4220                                let num_of_whitespaces = snapshot
 4221                                    .chars_for_range(range.clone())
 4222                                    .take_while(|c| c.is_whitespace())
 4223                                    .count();
 4224
 4225                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4226                                let column = start_point.column;
 4227                                let cursor_is_after_start_tag = {
 4228                                    let start_tag_len = start_tag.len();
 4229                                    let start_tag_line = snapshot
 4230                                        .chars_for_range(range.clone())
 4231                                        .skip(num_of_whitespaces)
 4232                                        .take(start_tag_len)
 4233                                        .collect::<String>();
 4234                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4235                                        num_of_whitespaces + start_tag_len <= column as usize
 4236                                    } else {
 4237                                        false
 4238                                    }
 4239                                };
 4240
 4241                                let cursor_is_after_delimiter = {
 4242                                    let delimiter_trim = delimiter.trim_end();
 4243                                    let delimiter_line = snapshot
 4244                                        .chars_for_range(range.clone())
 4245                                        .skip(num_of_whitespaces)
 4246                                        .take(delimiter_trim.len())
 4247                                        .collect::<String>();
 4248                                    if delimiter_line.starts_with(delimiter_trim) {
 4249                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4250                                    } else {
 4251                                        false
 4252                                    }
 4253                                };
 4254
 4255                                let cursor_is_before_end_tag_if_exists = {
 4256                                    let mut char_position = 0u32;
 4257                                    let mut end_tag_offset = None;
 4258
 4259                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4260                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4261                                            let chars_before_match =
 4262                                                chunk[..byte_pos].chars().count() as u32;
 4263                                            end_tag_offset =
 4264                                                Some(char_position + chars_before_match);
 4265                                            break 'outer;
 4266                                        }
 4267                                        char_position += chunk.chars().count() as u32;
 4268                                    }
 4269
 4270                                    if let Some(end_tag_offset) = end_tag_offset {
 4271                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4272                                        if cursor_is_after_start_tag {
 4273                                            if cursor_is_before_end_tag {
 4274                                                insert_extra_newline = true;
 4275                                            }
 4276                                            let cursor_is_at_start_of_end_tag =
 4277                                                column == end_tag_offset;
 4278                                            if cursor_is_at_start_of_end_tag {
 4279                                                indent_on_extra_newline.len = (*len).into();
 4280                                            }
 4281                                        }
 4282                                        cursor_is_before_end_tag
 4283                                    } else {
 4284                                        true
 4285                                    }
 4286                                };
 4287
 4288                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4289                                    && cursor_is_before_end_tag_if_exists
 4290                                {
 4291                                    if cursor_is_after_start_tag {
 4292                                        indent_on_newline.len = (*len).into();
 4293                                    }
 4294                                    Some(delimiter.clone())
 4295                                } else {
 4296                                    None
 4297                                }
 4298                            });
 4299
 4300                            (
 4301                                comment_delimiter,
 4302                                doc_delimiter,
 4303                                insert_extra_newline,
 4304                                indent_on_newline,
 4305                                indent_on_extra_newline,
 4306                            )
 4307                        } else {
 4308                            (
 4309                                None,
 4310                                None,
 4311                                false,
 4312                                IndentSize::default(),
 4313                                IndentSize::default(),
 4314                            )
 4315                        };
 4316
 4317                        let prevent_auto_indent = doc_delimiter.is_some();
 4318                        let delimiter = comment_delimiter.or(doc_delimiter);
 4319
 4320                        let capacity_for_delimiter =
 4321                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4322                        let mut new_text = String::with_capacity(
 4323                            1 + capacity_for_delimiter
 4324                                + existing_indent.len as usize
 4325                                + indent_on_newline.len as usize
 4326                                + indent_on_extra_newline.len as usize,
 4327                        );
 4328                        new_text.push('\n');
 4329                        new_text.extend(existing_indent.chars());
 4330                        new_text.extend(indent_on_newline.chars());
 4331
 4332                        if let Some(delimiter) = &delimiter {
 4333                            new_text.push_str(delimiter);
 4334                        }
 4335
 4336                        if insert_extra_newline {
 4337                            new_text.push('\n');
 4338                            new_text.extend(existing_indent.chars());
 4339                            new_text.extend(indent_on_extra_newline.chars());
 4340                        }
 4341
 4342                        let anchor = buffer.anchor_after(end);
 4343                        let new_selection = selection.map(|_| anchor);
 4344                        (
 4345                            ((start..end, new_text), prevent_auto_indent),
 4346                            (insert_extra_newline, new_selection),
 4347                        )
 4348                    })
 4349                    .unzip()
 4350            };
 4351
 4352            let mut auto_indent_edits = Vec::new();
 4353            let mut edits = Vec::new();
 4354            for (edit, prevent_auto_indent) in edits_with_flags {
 4355                if prevent_auto_indent {
 4356                    edits.push(edit);
 4357                } else {
 4358                    auto_indent_edits.push(edit);
 4359                }
 4360            }
 4361            if !edits.is_empty() {
 4362                this.edit(edits, cx);
 4363            }
 4364            if !auto_indent_edits.is_empty() {
 4365                this.edit_with_autoindent(auto_indent_edits, cx);
 4366            }
 4367
 4368            let buffer = this.buffer.read(cx).snapshot(cx);
 4369            let new_selections = selection_info
 4370                .into_iter()
 4371                .map(|(extra_newline_inserted, new_selection)| {
 4372                    let mut cursor = new_selection.end.to_point(&buffer);
 4373                    if extra_newline_inserted {
 4374                        cursor.row -= 1;
 4375                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4376                    }
 4377                    new_selection.map(|_| cursor)
 4378                })
 4379                .collect();
 4380
 4381            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4382                s.select(new_selections)
 4383            });
 4384            this.refresh_inline_completion(true, false, window, cx);
 4385        });
 4386    }
 4387
 4388    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4389        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4390
 4391        let buffer = self.buffer.read(cx);
 4392        let snapshot = buffer.snapshot(cx);
 4393
 4394        let mut edits = Vec::new();
 4395        let mut rows = Vec::new();
 4396
 4397        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4398            let cursor = selection.head();
 4399            let row = cursor.row;
 4400
 4401            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4402
 4403            let newline = "\n".to_string();
 4404            edits.push((start_of_line..start_of_line, newline));
 4405
 4406            rows.push(row + rows_inserted as u32);
 4407        }
 4408
 4409        self.transact(window, cx, |editor, window, cx| {
 4410            editor.edit(edits, cx);
 4411
 4412            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4413                let mut index = 0;
 4414                s.move_cursors_with(|map, _, _| {
 4415                    let row = rows[index];
 4416                    index += 1;
 4417
 4418                    let point = Point::new(row, 0);
 4419                    let boundary = map.next_line_boundary(point).1;
 4420                    let clipped = map.clip_point(boundary, Bias::Left);
 4421
 4422                    (clipped, SelectionGoal::None)
 4423                });
 4424            });
 4425
 4426            let mut indent_edits = Vec::new();
 4427            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4428            for row in rows {
 4429                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4430                for (row, indent) in indents {
 4431                    if indent.len == 0 {
 4432                        continue;
 4433                    }
 4434
 4435                    let text = match indent.kind {
 4436                        IndentKind::Space => " ".repeat(indent.len as usize),
 4437                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4438                    };
 4439                    let point = Point::new(row.0, 0);
 4440                    indent_edits.push((point..point, text));
 4441                }
 4442            }
 4443            editor.edit(indent_edits, cx);
 4444        });
 4445    }
 4446
 4447    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4448        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4449
 4450        let buffer = self.buffer.read(cx);
 4451        let snapshot = buffer.snapshot(cx);
 4452
 4453        let mut edits = Vec::new();
 4454        let mut rows = Vec::new();
 4455        let mut rows_inserted = 0;
 4456
 4457        for selection in self.selections.all_adjusted(cx) {
 4458            let cursor = selection.head();
 4459            let row = cursor.row;
 4460
 4461            let point = Point::new(row + 1, 0);
 4462            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4463
 4464            let newline = "\n".to_string();
 4465            edits.push((start_of_line..start_of_line, newline));
 4466
 4467            rows_inserted += 1;
 4468            rows.push(row + rows_inserted);
 4469        }
 4470
 4471        self.transact(window, cx, |editor, window, cx| {
 4472            editor.edit(edits, cx);
 4473
 4474            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4475                let mut index = 0;
 4476                s.move_cursors_with(|map, _, _| {
 4477                    let row = rows[index];
 4478                    index += 1;
 4479
 4480                    let point = Point::new(row, 0);
 4481                    let boundary = map.next_line_boundary(point).1;
 4482                    let clipped = map.clip_point(boundary, Bias::Left);
 4483
 4484                    (clipped, SelectionGoal::None)
 4485                });
 4486            });
 4487
 4488            let mut indent_edits = Vec::new();
 4489            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4490            for row in rows {
 4491                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4492                for (row, indent) in indents {
 4493                    if indent.len == 0 {
 4494                        continue;
 4495                    }
 4496
 4497                    let text = match indent.kind {
 4498                        IndentKind::Space => " ".repeat(indent.len as usize),
 4499                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4500                    };
 4501                    let point = Point::new(row.0, 0);
 4502                    indent_edits.push((point..point, text));
 4503                }
 4504            }
 4505            editor.edit(indent_edits, cx);
 4506        });
 4507    }
 4508
 4509    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4510        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4511            original_indent_columns: Vec::new(),
 4512        });
 4513        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4514    }
 4515
 4516    fn insert_with_autoindent_mode(
 4517        &mut self,
 4518        text: &str,
 4519        autoindent_mode: Option<AutoindentMode>,
 4520        window: &mut Window,
 4521        cx: &mut Context<Self>,
 4522    ) {
 4523        if self.read_only(cx) {
 4524            return;
 4525        }
 4526
 4527        let text: Arc<str> = text.into();
 4528        self.transact(window, cx, |this, window, cx| {
 4529            let old_selections = this.selections.all_adjusted(cx);
 4530            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4531                let anchors = {
 4532                    let snapshot = buffer.read(cx);
 4533                    old_selections
 4534                        .iter()
 4535                        .map(|s| {
 4536                            let anchor = snapshot.anchor_after(s.head());
 4537                            s.map(|_| anchor)
 4538                        })
 4539                        .collect::<Vec<_>>()
 4540                };
 4541                buffer.edit(
 4542                    old_selections
 4543                        .iter()
 4544                        .map(|s| (s.start..s.end, text.clone())),
 4545                    autoindent_mode,
 4546                    cx,
 4547                );
 4548                anchors
 4549            });
 4550
 4551            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4552                s.select_anchors(selection_anchors);
 4553            });
 4554
 4555            cx.notify();
 4556        });
 4557    }
 4558
 4559    fn trigger_completion_on_input(
 4560        &mut self,
 4561        text: &str,
 4562        trigger_in_words: bool,
 4563        window: &mut Window,
 4564        cx: &mut Context<Self>,
 4565    ) {
 4566        let completions_source = self
 4567            .context_menu
 4568            .borrow()
 4569            .as_ref()
 4570            .and_then(|menu| match menu {
 4571                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4572                CodeContextMenu::CodeActions(_) => None,
 4573            });
 4574
 4575        match completions_source {
 4576            Some(CompletionsMenuSource::Words) => {
 4577                self.show_word_completions(&ShowWordCompletions, window, cx)
 4578            }
 4579            Some(CompletionsMenuSource::Normal)
 4580            | Some(CompletionsMenuSource::SnippetChoices)
 4581            | None
 4582                if self.is_completion_trigger(
 4583                    text,
 4584                    trigger_in_words,
 4585                    completions_source.is_some(),
 4586                    cx,
 4587                ) =>
 4588            {
 4589                self.show_completions(
 4590                    &ShowCompletions {
 4591                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4592                    },
 4593                    window,
 4594                    cx,
 4595                )
 4596            }
 4597            _ => {
 4598                self.hide_context_menu(window, cx);
 4599            }
 4600        }
 4601    }
 4602
 4603    fn is_completion_trigger(
 4604        &self,
 4605        text: &str,
 4606        trigger_in_words: bool,
 4607        menu_is_open: bool,
 4608        cx: &mut Context<Self>,
 4609    ) -> bool {
 4610        let position = self.selections.newest_anchor().head();
 4611        let multibuffer = self.buffer.read(cx);
 4612        let Some(buffer) = position
 4613            .buffer_id
 4614            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4615        else {
 4616            return false;
 4617        };
 4618
 4619        if let Some(completion_provider) = &self.completion_provider {
 4620            completion_provider.is_completion_trigger(
 4621                &buffer,
 4622                position.text_anchor,
 4623                text,
 4624                trigger_in_words,
 4625                menu_is_open,
 4626                cx,
 4627            )
 4628        } else {
 4629            false
 4630        }
 4631    }
 4632
 4633    /// If any empty selections is touching the start of its innermost containing autoclose
 4634    /// region, expand it to select the brackets.
 4635    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4636        let selections = self.selections.all::<usize>(cx);
 4637        let buffer = self.buffer.read(cx).read(cx);
 4638        let new_selections = self
 4639            .selections_with_autoclose_regions(selections, &buffer)
 4640            .map(|(mut selection, region)| {
 4641                if !selection.is_empty() {
 4642                    return selection;
 4643                }
 4644
 4645                if let Some(region) = region {
 4646                    let mut range = region.range.to_offset(&buffer);
 4647                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4648                        range.start -= region.pair.start.len();
 4649                        if buffer.contains_str_at(range.start, &region.pair.start)
 4650                            && buffer.contains_str_at(range.end, &region.pair.end)
 4651                        {
 4652                            range.end += region.pair.end.len();
 4653                            selection.start = range.start;
 4654                            selection.end = range.end;
 4655
 4656                            return selection;
 4657                        }
 4658                    }
 4659                }
 4660
 4661                let always_treat_brackets_as_autoclosed = buffer
 4662                    .language_settings_at(selection.start, cx)
 4663                    .always_treat_brackets_as_autoclosed;
 4664
 4665                if !always_treat_brackets_as_autoclosed {
 4666                    return selection;
 4667                }
 4668
 4669                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4670                    for (pair, enabled) in scope.brackets() {
 4671                        if !enabled || !pair.close {
 4672                            continue;
 4673                        }
 4674
 4675                        if buffer.contains_str_at(selection.start, &pair.end) {
 4676                            let pair_start_len = pair.start.len();
 4677                            if buffer.contains_str_at(
 4678                                selection.start.saturating_sub(pair_start_len),
 4679                                &pair.start,
 4680                            ) {
 4681                                selection.start -= pair_start_len;
 4682                                selection.end += pair.end.len();
 4683
 4684                                return selection;
 4685                            }
 4686                        }
 4687                    }
 4688                }
 4689
 4690                selection
 4691            })
 4692            .collect();
 4693
 4694        drop(buffer);
 4695        self.change_selections(None, window, cx, |selections| {
 4696            selections.select(new_selections)
 4697        });
 4698    }
 4699
 4700    /// Iterate the given selections, and for each one, find the smallest surrounding
 4701    /// autoclose region. This uses the ordering of the selections and the autoclose
 4702    /// regions to avoid repeated comparisons.
 4703    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4704        &'a self,
 4705        selections: impl IntoIterator<Item = Selection<D>>,
 4706        buffer: &'a MultiBufferSnapshot,
 4707    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4708        let mut i = 0;
 4709        let mut regions = self.autoclose_regions.as_slice();
 4710        selections.into_iter().map(move |selection| {
 4711            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4712
 4713            let mut enclosing = None;
 4714            while let Some(pair_state) = regions.get(i) {
 4715                if pair_state.range.end.to_offset(buffer) < range.start {
 4716                    regions = &regions[i + 1..];
 4717                    i = 0;
 4718                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4719                    break;
 4720                } else {
 4721                    if pair_state.selection_id == selection.id {
 4722                        enclosing = Some(pair_state);
 4723                    }
 4724                    i += 1;
 4725                }
 4726            }
 4727
 4728            (selection, enclosing)
 4729        })
 4730    }
 4731
 4732    /// Remove any autoclose regions that no longer contain their selection.
 4733    fn invalidate_autoclose_regions(
 4734        &mut self,
 4735        mut selections: &[Selection<Anchor>],
 4736        buffer: &MultiBufferSnapshot,
 4737    ) {
 4738        self.autoclose_regions.retain(|state| {
 4739            let mut i = 0;
 4740            while let Some(selection) = selections.get(i) {
 4741                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4742                    selections = &selections[1..];
 4743                    continue;
 4744                }
 4745                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4746                    break;
 4747                }
 4748                if selection.id == state.selection_id {
 4749                    return true;
 4750                } else {
 4751                    i += 1;
 4752                }
 4753            }
 4754            false
 4755        });
 4756    }
 4757
 4758    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4759        let offset = position.to_offset(buffer);
 4760        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4761        if offset > word_range.start && kind == Some(CharKind::Word) {
 4762            Some(
 4763                buffer
 4764                    .text_for_range(word_range.start..offset)
 4765                    .collect::<String>(),
 4766            )
 4767        } else {
 4768            None
 4769        }
 4770    }
 4771
 4772    pub fn toggle_inline_values(
 4773        &mut self,
 4774        _: &ToggleInlineValues,
 4775        _: &mut Window,
 4776        cx: &mut Context<Self>,
 4777    ) {
 4778        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4779
 4780        self.refresh_inline_values(cx);
 4781    }
 4782
 4783    pub fn toggle_inlay_hints(
 4784        &mut self,
 4785        _: &ToggleInlayHints,
 4786        _: &mut Window,
 4787        cx: &mut Context<Self>,
 4788    ) {
 4789        self.refresh_inlay_hints(
 4790            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4791            cx,
 4792        );
 4793    }
 4794
 4795    pub fn inlay_hints_enabled(&self) -> bool {
 4796        self.inlay_hint_cache.enabled
 4797    }
 4798
 4799    pub fn inline_values_enabled(&self) -> bool {
 4800        self.inline_value_cache.enabled
 4801    }
 4802
 4803    #[cfg(any(test, feature = "test-support"))]
 4804    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4805        self.display_map
 4806            .read(cx)
 4807            .current_inlays()
 4808            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4809            .cloned()
 4810            .collect()
 4811    }
 4812
 4813    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4814        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4815            return;
 4816        }
 4817
 4818        let reason_description = reason.description();
 4819        let ignore_debounce = matches!(
 4820            reason,
 4821            InlayHintRefreshReason::SettingsChange(_)
 4822                | InlayHintRefreshReason::Toggle(_)
 4823                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4824                | InlayHintRefreshReason::ModifiersChanged(_)
 4825        );
 4826        let (invalidate_cache, required_languages) = match reason {
 4827            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4828                match self.inlay_hint_cache.modifiers_override(enabled) {
 4829                    Some(enabled) => {
 4830                        if enabled {
 4831                            (InvalidationStrategy::RefreshRequested, None)
 4832                        } else {
 4833                            self.splice_inlays(
 4834                                &self
 4835                                    .visible_inlay_hints(cx)
 4836                                    .iter()
 4837                                    .map(|inlay| inlay.id)
 4838                                    .collect::<Vec<InlayId>>(),
 4839                                Vec::new(),
 4840                                cx,
 4841                            );
 4842                            return;
 4843                        }
 4844                    }
 4845                    None => return,
 4846                }
 4847            }
 4848            InlayHintRefreshReason::Toggle(enabled) => {
 4849                if self.inlay_hint_cache.toggle(enabled) {
 4850                    if enabled {
 4851                        (InvalidationStrategy::RefreshRequested, None)
 4852                    } else {
 4853                        self.splice_inlays(
 4854                            &self
 4855                                .visible_inlay_hints(cx)
 4856                                .iter()
 4857                                .map(|inlay| inlay.id)
 4858                                .collect::<Vec<InlayId>>(),
 4859                            Vec::new(),
 4860                            cx,
 4861                        );
 4862                        return;
 4863                    }
 4864                } else {
 4865                    return;
 4866                }
 4867            }
 4868            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4869                match self.inlay_hint_cache.update_settings(
 4870                    &self.buffer,
 4871                    new_settings,
 4872                    self.visible_inlay_hints(cx),
 4873                    cx,
 4874                ) {
 4875                    ControlFlow::Break(Some(InlaySplice {
 4876                        to_remove,
 4877                        to_insert,
 4878                    })) => {
 4879                        self.splice_inlays(&to_remove, to_insert, cx);
 4880                        return;
 4881                    }
 4882                    ControlFlow::Break(None) => return,
 4883                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4884                }
 4885            }
 4886            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4887                if let Some(InlaySplice {
 4888                    to_remove,
 4889                    to_insert,
 4890                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4891                {
 4892                    self.splice_inlays(&to_remove, to_insert, cx);
 4893                }
 4894                self.display_map.update(cx, |display_map, _| {
 4895                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4896                });
 4897                return;
 4898            }
 4899            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4900            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4901                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4902            }
 4903            InlayHintRefreshReason::RefreshRequested => {
 4904                (InvalidationStrategy::RefreshRequested, None)
 4905            }
 4906        };
 4907
 4908        if let Some(InlaySplice {
 4909            to_remove,
 4910            to_insert,
 4911        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4912            reason_description,
 4913            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4914            invalidate_cache,
 4915            ignore_debounce,
 4916            cx,
 4917        ) {
 4918            self.splice_inlays(&to_remove, to_insert, cx);
 4919        }
 4920    }
 4921
 4922    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4923        self.display_map
 4924            .read(cx)
 4925            .current_inlays()
 4926            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4927            .cloned()
 4928            .collect()
 4929    }
 4930
 4931    pub fn excerpts_for_inlay_hints_query(
 4932        &self,
 4933        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4934        cx: &mut Context<Editor>,
 4935    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4936        let Some(project) = self.project.as_ref() else {
 4937            return HashMap::default();
 4938        };
 4939        let project = project.read(cx);
 4940        let multi_buffer = self.buffer().read(cx);
 4941        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4942        let multi_buffer_visible_start = self
 4943            .scroll_manager
 4944            .anchor()
 4945            .anchor
 4946            .to_point(&multi_buffer_snapshot);
 4947        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4948            multi_buffer_visible_start
 4949                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4950            Bias::Left,
 4951        );
 4952        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4953        multi_buffer_snapshot
 4954            .range_to_buffer_ranges(multi_buffer_visible_range)
 4955            .into_iter()
 4956            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4957            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4958                let buffer_file = project::File::from_dyn(buffer.file())?;
 4959                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4960                let worktree_entry = buffer_worktree
 4961                    .read(cx)
 4962                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4963                if worktree_entry.is_ignored {
 4964                    return None;
 4965                }
 4966
 4967                let language = buffer.language()?;
 4968                if let Some(restrict_to_languages) = restrict_to_languages {
 4969                    if !restrict_to_languages.contains(language) {
 4970                        return None;
 4971                    }
 4972                }
 4973                Some((
 4974                    excerpt_id,
 4975                    (
 4976                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4977                        buffer.version().clone(),
 4978                        excerpt_visible_range,
 4979                    ),
 4980                ))
 4981            })
 4982            .collect()
 4983    }
 4984
 4985    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4986        TextLayoutDetails {
 4987            text_system: window.text_system().clone(),
 4988            editor_style: self.style.clone().unwrap(),
 4989            rem_size: window.rem_size(),
 4990            scroll_anchor: self.scroll_manager.anchor(),
 4991            visible_rows: self.visible_line_count(),
 4992            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4993        }
 4994    }
 4995
 4996    pub fn splice_inlays(
 4997        &self,
 4998        to_remove: &[InlayId],
 4999        to_insert: Vec<Inlay>,
 5000        cx: &mut Context<Self>,
 5001    ) {
 5002        self.display_map.update(cx, |display_map, cx| {
 5003            display_map.splice_inlays(to_remove, to_insert, cx)
 5004        });
 5005        cx.notify();
 5006    }
 5007
 5008    fn trigger_on_type_formatting(
 5009        &self,
 5010        input: String,
 5011        window: &mut Window,
 5012        cx: &mut Context<Self>,
 5013    ) -> Option<Task<Result<()>>> {
 5014        if input.len() != 1 {
 5015            return None;
 5016        }
 5017
 5018        let project = self.project.as_ref()?;
 5019        let position = self.selections.newest_anchor().head();
 5020        let (buffer, buffer_position) = self
 5021            .buffer
 5022            .read(cx)
 5023            .text_anchor_for_position(position, cx)?;
 5024
 5025        let settings = language_settings::language_settings(
 5026            buffer
 5027                .read(cx)
 5028                .language_at(buffer_position)
 5029                .map(|l| l.name()),
 5030            buffer.read(cx).file(),
 5031            cx,
 5032        );
 5033        if !settings.use_on_type_format {
 5034            return None;
 5035        }
 5036
 5037        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5038        // hence we do LSP request & edit on host side only — add formats to host's history.
 5039        let push_to_lsp_host_history = true;
 5040        // If this is not the host, append its history with new edits.
 5041        let push_to_client_history = project.read(cx).is_via_collab();
 5042
 5043        let on_type_formatting = project.update(cx, |project, cx| {
 5044            project.on_type_format(
 5045                buffer.clone(),
 5046                buffer_position,
 5047                input,
 5048                push_to_lsp_host_history,
 5049                cx,
 5050            )
 5051        });
 5052        Some(cx.spawn_in(window, async move |editor, cx| {
 5053            if let Some(transaction) = on_type_formatting.await? {
 5054                if push_to_client_history {
 5055                    buffer
 5056                        .update(cx, |buffer, _| {
 5057                            buffer.push_transaction(transaction, Instant::now());
 5058                            buffer.finalize_last_transaction();
 5059                        })
 5060                        .ok();
 5061                }
 5062                editor.update(cx, |editor, cx| {
 5063                    editor.refresh_document_highlights(cx);
 5064                })?;
 5065            }
 5066            Ok(())
 5067        }))
 5068    }
 5069
 5070    pub fn show_word_completions(
 5071        &mut self,
 5072        _: &ShowWordCompletions,
 5073        window: &mut Window,
 5074        cx: &mut Context<Self>,
 5075    ) {
 5076        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5077    }
 5078
 5079    pub fn show_completions(
 5080        &mut self,
 5081        options: &ShowCompletions,
 5082        window: &mut Window,
 5083        cx: &mut Context<Self>,
 5084    ) {
 5085        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5086    }
 5087
 5088    fn open_or_update_completions_menu(
 5089        &mut self,
 5090        requested_source: Option<CompletionsMenuSource>,
 5091        trigger: Option<&str>,
 5092        window: &mut Window,
 5093        cx: &mut Context<Self>,
 5094    ) {
 5095        if self.pending_rename.is_some() {
 5096            return;
 5097        }
 5098
 5099        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5100
 5101        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5102        // inserted and selected. To handle that case, the start of the selection is used so that
 5103        // the menu starts with all choices.
 5104        let position = self
 5105            .selections
 5106            .newest_anchor()
 5107            .start
 5108            .bias_right(&multibuffer_snapshot);
 5109        if position.diff_base_anchor.is_some() {
 5110            return;
 5111        }
 5112        let (buffer, buffer_position) =
 5113            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5114                output
 5115            } else {
 5116                return;
 5117            };
 5118        let buffer_snapshot = buffer.read(cx).snapshot();
 5119
 5120        let query: Option<Arc<String>> =
 5121            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5122
 5123        drop(multibuffer_snapshot);
 5124
 5125        let provider = match requested_source {
 5126            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5127            Some(CompletionsMenuSource::Words) => None,
 5128            Some(CompletionsMenuSource::SnippetChoices) => {
 5129                log::error!("bug: SnippetChoices requested_source is not handled");
 5130                None
 5131            }
 5132        };
 5133
 5134        let sort_completions = provider
 5135            .as_ref()
 5136            .map_or(false, |provider| provider.sort_completions());
 5137
 5138        let filter_completions = provider
 5139            .as_ref()
 5140            .map_or(true, |provider| provider.filter_completions());
 5141
 5142        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5143            if filter_completions {
 5144                menu.filter(query.clone(), provider.clone(), window, cx);
 5145            }
 5146            // When `is_incomplete` is false, no need to re-query completions when the current query
 5147            // is a suffix of the initial query.
 5148            if !menu.is_incomplete {
 5149                // If the new query is a suffix of the old query (typing more characters) and
 5150                // the previous result was complete, the existing completions can be filtered.
 5151                //
 5152                // Note that this is always true for snippet completions.
 5153                let query_matches = match (&menu.initial_query, &query) {
 5154                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5155                    (None, _) => true,
 5156                    _ => false,
 5157                };
 5158                if query_matches {
 5159                    let position_matches = if menu.initial_position == position {
 5160                        true
 5161                    } else {
 5162                        let snapshot = self.buffer.read(cx).read(cx);
 5163                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5164                    };
 5165                    if position_matches {
 5166                        return;
 5167                    }
 5168                }
 5169            }
 5170        };
 5171
 5172        let trigger_kind = match trigger {
 5173            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5174                CompletionTriggerKind::TRIGGER_CHARACTER
 5175            }
 5176            _ => CompletionTriggerKind::INVOKED,
 5177        };
 5178        let completion_context = CompletionContext {
 5179            trigger_character: trigger.and_then(|trigger| {
 5180                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5181                    Some(String::from(trigger))
 5182                } else {
 5183                    None
 5184                }
 5185            }),
 5186            trigger_kind,
 5187        };
 5188
 5189        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5190            buffer_snapshot.surrounding_word(buffer_position)
 5191        {
 5192            let word_to_exclude = buffer_snapshot
 5193                .text_for_range(word_range.clone())
 5194                .collect::<String>();
 5195            (
 5196                buffer_snapshot.anchor_before(word_range.start)
 5197                    ..buffer_snapshot.anchor_after(buffer_position),
 5198                Some(word_to_exclude),
 5199            )
 5200        } else {
 5201            (buffer_position..buffer_position, None)
 5202        };
 5203
 5204        let language = buffer_snapshot
 5205            .language_at(buffer_position)
 5206            .map(|language| language.name());
 5207
 5208        let completion_settings =
 5209            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5210
 5211        let show_completion_documentation = buffer_snapshot
 5212            .settings_at(buffer_position, cx)
 5213            .show_completion_documentation;
 5214
 5215        // The document can be large, so stay in reasonable bounds when searching for words,
 5216        // otherwise completion pop-up might be slow to appear.
 5217        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5218        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5219        let min_word_search = buffer_snapshot.clip_point(
 5220            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5221            Bias::Left,
 5222        );
 5223        let max_word_search = buffer_snapshot.clip_point(
 5224            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5225            Bias::Right,
 5226        );
 5227        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5228            ..buffer_snapshot.point_to_offset(max_word_search);
 5229
 5230        let skip_digits = query
 5231            .as_ref()
 5232            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5233
 5234        let (mut words, provider_responses) = match &provider {
 5235            Some(provider) => {
 5236                let provider_responses = provider.completions(
 5237                    position.excerpt_id,
 5238                    &buffer,
 5239                    buffer_position,
 5240                    completion_context,
 5241                    window,
 5242                    cx,
 5243                );
 5244
 5245                let words = match completion_settings.words {
 5246                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5247                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5248                        .background_spawn(async move {
 5249                            buffer_snapshot.words_in_range(WordsQuery {
 5250                                fuzzy_contents: None,
 5251                                range: word_search_range,
 5252                                skip_digits,
 5253                            })
 5254                        }),
 5255                };
 5256
 5257                (words, provider_responses)
 5258            }
 5259            None => (
 5260                cx.background_spawn(async move {
 5261                    buffer_snapshot.words_in_range(WordsQuery {
 5262                        fuzzy_contents: None,
 5263                        range: word_search_range,
 5264                        skip_digits,
 5265                    })
 5266                }),
 5267                Task::ready(Ok(Vec::new())),
 5268            ),
 5269        };
 5270
 5271        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5272
 5273        let id = post_inc(&mut self.next_completion_id);
 5274        let task = cx.spawn_in(window, async move |editor, cx| {
 5275            let Ok(()) = editor.update(cx, |this, _| {
 5276                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5277            }) else {
 5278                return;
 5279            };
 5280
 5281            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5282            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5283            let mut completions = Vec::new();
 5284            let mut is_incomplete = false;
 5285            if let Some(provider_responses) = provider_responses.await.log_err() {
 5286                if !provider_responses.is_empty() {
 5287                    for response in provider_responses {
 5288                        completions.extend(response.completions);
 5289                        is_incomplete = is_incomplete || response.is_incomplete;
 5290                    }
 5291                    if completion_settings.words == WordsCompletionMode::Fallback {
 5292                        words = Task::ready(BTreeMap::default());
 5293                    }
 5294                }
 5295            }
 5296
 5297            let mut words = words.await;
 5298            if let Some(word_to_exclude) = &word_to_exclude {
 5299                words.remove(word_to_exclude);
 5300            }
 5301            for lsp_completion in &completions {
 5302                words.remove(&lsp_completion.new_text);
 5303            }
 5304            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5305                replace_range: word_replace_range.clone(),
 5306                new_text: word.clone(),
 5307                label: CodeLabel::plain(word, None),
 5308                icon_path: None,
 5309                documentation: None,
 5310                source: CompletionSource::BufferWord {
 5311                    word_range,
 5312                    resolved: false,
 5313                },
 5314                insert_text_mode: Some(InsertTextMode::AS_IS),
 5315                confirm: None,
 5316            }));
 5317
 5318            let menu = if completions.is_empty() {
 5319                None
 5320            } else {
 5321                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5322                    let languages = editor
 5323                        .workspace
 5324                        .as_ref()
 5325                        .and_then(|(workspace, _)| workspace.upgrade())
 5326                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5327                    let menu = CompletionsMenu::new(
 5328                        id,
 5329                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5330                        sort_completions,
 5331                        show_completion_documentation,
 5332                        position,
 5333                        query.clone(),
 5334                        is_incomplete,
 5335                        buffer.clone(),
 5336                        completions.into(),
 5337                        snippet_sort_order,
 5338                        languages,
 5339                        language,
 5340                        cx,
 5341                    );
 5342
 5343                    let query = if filter_completions { query } else { None };
 5344                    let matches_task = if let Some(query) = query {
 5345                        menu.do_async_filtering(query, cx)
 5346                    } else {
 5347                        Task::ready(menu.unfiltered_matches())
 5348                    };
 5349                    (menu, matches_task)
 5350                }) else {
 5351                    return;
 5352                };
 5353
 5354                let matches = matches_task.await;
 5355
 5356                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5357                    // Newer menu already set, so exit.
 5358                    match editor.context_menu.borrow().as_ref() {
 5359                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5360                            if prev_menu.id > id {
 5361                                return;
 5362                            }
 5363                        }
 5364                        _ => {}
 5365                    };
 5366
 5367                    // Only valid to take prev_menu because it the new menu is immediately set
 5368                    // below, or the menu is hidden.
 5369                    match editor.context_menu.borrow_mut().take() {
 5370                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5371                            let position_matches =
 5372                                if prev_menu.initial_position == menu.initial_position {
 5373                                    true
 5374                                } else {
 5375                                    let snapshot = editor.buffer.read(cx).read(cx);
 5376                                    prev_menu.initial_position.to_offset(&snapshot)
 5377                                        == menu.initial_position.to_offset(&snapshot)
 5378                                };
 5379                            if position_matches {
 5380                                // Preserve markdown cache before `set_filter_results` because it will
 5381                                // try to populate the documentation cache.
 5382                                menu.preserve_markdown_cache(prev_menu);
 5383                            }
 5384                        }
 5385                        _ => {}
 5386                    };
 5387
 5388                    menu.set_filter_results(matches, provider, window, cx);
 5389                }) else {
 5390                    return;
 5391                };
 5392
 5393                menu.visible().then_some(menu)
 5394            };
 5395
 5396            editor
 5397                .update_in(cx, |editor, window, cx| {
 5398                    if editor.focus_handle.is_focused(window) {
 5399                        if let Some(menu) = menu {
 5400                            *editor.context_menu.borrow_mut() =
 5401                                Some(CodeContextMenu::Completions(menu));
 5402
 5403                            crate::hover_popover::hide_hover(editor, cx);
 5404                            if editor.show_edit_predictions_in_menu() {
 5405                                editor.update_visible_inline_completion(window, cx);
 5406                            } else {
 5407                                editor.discard_inline_completion(false, cx);
 5408                            }
 5409
 5410                            cx.notify();
 5411                            return;
 5412                        }
 5413                    }
 5414
 5415                    if editor.completion_tasks.len() <= 1 {
 5416                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5417                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5418                        // If it was already hidden and we don't show inline completions in the menu, we should
 5419                        // also show the inline-completion when available.
 5420                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5421                            editor.update_visible_inline_completion(window, cx);
 5422                        }
 5423                    }
 5424                })
 5425                .ok();
 5426        });
 5427
 5428        self.completion_tasks.push((id, task));
 5429    }
 5430
 5431    #[cfg(feature = "test-support")]
 5432    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5433        let menu = self.context_menu.borrow();
 5434        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5435            let completions = menu.completions.borrow();
 5436            Some(completions.to_vec())
 5437        } else {
 5438            None
 5439        }
 5440    }
 5441
 5442    pub fn with_completions_menu_matching_id<R>(
 5443        &self,
 5444        id: CompletionId,
 5445        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5446    ) -> R {
 5447        let mut context_menu = self.context_menu.borrow_mut();
 5448        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5449            return f(None);
 5450        };
 5451        if completions_menu.id != id {
 5452            return f(None);
 5453        }
 5454        f(Some(completions_menu))
 5455    }
 5456
 5457    pub fn confirm_completion(
 5458        &mut self,
 5459        action: &ConfirmCompletion,
 5460        window: &mut Window,
 5461        cx: &mut Context<Self>,
 5462    ) -> Option<Task<Result<()>>> {
 5463        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5464        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5465    }
 5466
 5467    pub fn confirm_completion_insert(
 5468        &mut self,
 5469        _: &ConfirmCompletionInsert,
 5470        window: &mut Window,
 5471        cx: &mut Context<Self>,
 5472    ) -> Option<Task<Result<()>>> {
 5473        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5474        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5475    }
 5476
 5477    pub fn confirm_completion_replace(
 5478        &mut self,
 5479        _: &ConfirmCompletionReplace,
 5480        window: &mut Window,
 5481        cx: &mut Context<Self>,
 5482    ) -> Option<Task<Result<()>>> {
 5483        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5484        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5485    }
 5486
 5487    pub fn compose_completion(
 5488        &mut self,
 5489        action: &ComposeCompletion,
 5490        window: &mut Window,
 5491        cx: &mut Context<Self>,
 5492    ) -> Option<Task<Result<()>>> {
 5493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5494        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5495    }
 5496
 5497    fn do_completion(
 5498        &mut self,
 5499        item_ix: Option<usize>,
 5500        intent: CompletionIntent,
 5501        window: &mut Window,
 5502        cx: &mut Context<Editor>,
 5503    ) -> Option<Task<Result<()>>> {
 5504        use language::ToOffset as _;
 5505
 5506        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5507        else {
 5508            return None;
 5509        };
 5510
 5511        let candidate_id = {
 5512            let entries = completions_menu.entries.borrow();
 5513            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5514            if self.show_edit_predictions_in_menu() {
 5515                self.discard_inline_completion(true, cx);
 5516            }
 5517            mat.candidate_id
 5518        };
 5519
 5520        let completion = completions_menu
 5521            .completions
 5522            .borrow()
 5523            .get(candidate_id)?
 5524            .clone();
 5525        cx.stop_propagation();
 5526
 5527        let buffer_handle = completions_menu.buffer.clone();
 5528
 5529        let CompletionEdit {
 5530            new_text,
 5531            snippet,
 5532            replace_range,
 5533        } = process_completion_for_edit(
 5534            &completion,
 5535            intent,
 5536            &buffer_handle,
 5537            &completions_menu.initial_position.text_anchor,
 5538            cx,
 5539        );
 5540
 5541        let buffer = buffer_handle.read(cx);
 5542        let snapshot = self.buffer.read(cx).snapshot(cx);
 5543        let newest_anchor = self.selections.newest_anchor();
 5544        let replace_range_multibuffer = {
 5545            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5546            let multibuffer_anchor = snapshot
 5547                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5548                .unwrap()
 5549                ..snapshot
 5550                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5551                    .unwrap();
 5552            multibuffer_anchor.start.to_offset(&snapshot)
 5553                ..multibuffer_anchor.end.to_offset(&snapshot)
 5554        };
 5555        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5556            return None;
 5557        }
 5558
 5559        let old_text = buffer
 5560            .text_for_range(replace_range.clone())
 5561            .collect::<String>();
 5562        let lookbehind = newest_anchor
 5563            .start
 5564            .text_anchor
 5565            .to_offset(buffer)
 5566            .saturating_sub(replace_range.start);
 5567        let lookahead = replace_range
 5568            .end
 5569            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5570        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5571        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5572
 5573        let selections = self.selections.all::<usize>(cx);
 5574        let mut ranges = Vec::new();
 5575        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5576
 5577        for selection in &selections {
 5578            let range = if selection.id == newest_anchor.id {
 5579                replace_range_multibuffer.clone()
 5580            } else {
 5581                let mut range = selection.range();
 5582
 5583                // if prefix is present, don't duplicate it
 5584                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5585                    range.start = range.start.saturating_sub(lookbehind);
 5586
 5587                    // if suffix is also present, mimic the newest cursor and replace it
 5588                    if selection.id != newest_anchor.id
 5589                        && snapshot.contains_str_at(range.end, suffix)
 5590                    {
 5591                        range.end += lookahead;
 5592                    }
 5593                }
 5594                range
 5595            };
 5596
 5597            ranges.push(range.clone());
 5598
 5599            if !self.linked_edit_ranges.is_empty() {
 5600                let start_anchor = snapshot.anchor_before(range.start);
 5601                let end_anchor = snapshot.anchor_after(range.end);
 5602                if let Some(ranges) = self
 5603                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5604                {
 5605                    for (buffer, edits) in ranges {
 5606                        linked_edits
 5607                            .entry(buffer.clone())
 5608                            .or_default()
 5609                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5610                    }
 5611                }
 5612            }
 5613        }
 5614
 5615        let common_prefix_len = old_text
 5616            .chars()
 5617            .zip(new_text.chars())
 5618            .take_while(|(a, b)| a == b)
 5619            .map(|(a, _)| a.len_utf8())
 5620            .sum::<usize>();
 5621
 5622        cx.emit(EditorEvent::InputHandled {
 5623            utf16_range_to_replace: None,
 5624            text: new_text[common_prefix_len..].into(),
 5625        });
 5626
 5627        self.transact(window, cx, |this, window, cx| {
 5628            if let Some(mut snippet) = snippet {
 5629                snippet.text = new_text.to_string();
 5630                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5631            } else {
 5632                this.buffer.update(cx, |buffer, cx| {
 5633                    let auto_indent = match completion.insert_text_mode {
 5634                        Some(InsertTextMode::AS_IS) => None,
 5635                        _ => this.autoindent_mode.clone(),
 5636                    };
 5637                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5638                    buffer.edit(edits, auto_indent, cx);
 5639                });
 5640            }
 5641            for (buffer, edits) in linked_edits {
 5642                buffer.update(cx, |buffer, cx| {
 5643                    let snapshot = buffer.snapshot();
 5644                    let edits = edits
 5645                        .into_iter()
 5646                        .map(|(range, text)| {
 5647                            use text::ToPoint as TP;
 5648                            let end_point = TP::to_point(&range.end, &snapshot);
 5649                            let start_point = TP::to_point(&range.start, &snapshot);
 5650                            (start_point..end_point, text)
 5651                        })
 5652                        .sorted_by_key(|(range, _)| range.start);
 5653                    buffer.edit(edits, None, cx);
 5654                })
 5655            }
 5656
 5657            this.refresh_inline_completion(true, false, window, cx);
 5658        });
 5659
 5660        let show_new_completions_on_confirm = completion
 5661            .confirm
 5662            .as_ref()
 5663            .map_or(false, |confirm| confirm(intent, window, cx));
 5664        if show_new_completions_on_confirm {
 5665            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5666        }
 5667
 5668        let provider = self.completion_provider.as_ref()?;
 5669        drop(completion);
 5670        let apply_edits = provider.apply_additional_edits_for_completion(
 5671            buffer_handle,
 5672            completions_menu.completions.clone(),
 5673            candidate_id,
 5674            true,
 5675            cx,
 5676        );
 5677
 5678        let editor_settings = EditorSettings::get_global(cx);
 5679        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5680            // After the code completion is finished, users often want to know what signatures are needed.
 5681            // so we should automatically call signature_help
 5682            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5683        }
 5684
 5685        Some(cx.foreground_executor().spawn(async move {
 5686            apply_edits.await?;
 5687            Ok(())
 5688        }))
 5689    }
 5690
 5691    pub fn toggle_code_actions(
 5692        &mut self,
 5693        action: &ToggleCodeActions,
 5694        window: &mut Window,
 5695        cx: &mut Context<Self>,
 5696    ) {
 5697        let quick_launch = action.quick_launch;
 5698        let mut context_menu = self.context_menu.borrow_mut();
 5699        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5700            if code_actions.deployed_from == action.deployed_from {
 5701                // Toggle if we're selecting the same one
 5702                *context_menu = None;
 5703                cx.notify();
 5704                return;
 5705            } else {
 5706                // Otherwise, clear it and start a new one
 5707                *context_menu = None;
 5708                cx.notify();
 5709            }
 5710        }
 5711        drop(context_menu);
 5712        let snapshot = self.snapshot(window, cx);
 5713        let deployed_from = action.deployed_from.clone();
 5714        let mut task = self.code_actions_task.take();
 5715        let action = action.clone();
 5716        cx.spawn_in(window, async move |editor, cx| {
 5717            while let Some(prev_task) = task {
 5718                prev_task.await.log_err();
 5719                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5720            }
 5721
 5722            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5723                if editor.focus_handle.is_focused(window) {
 5724                    let multibuffer_point = match &action.deployed_from {
 5725                        Some(CodeActionSource::Indicator(row)) => {
 5726                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5727                        }
 5728                        _ => editor.selections.newest::<Point>(cx).head(),
 5729                    };
 5730                    let (buffer, buffer_row) = snapshot
 5731                        .buffer_snapshot
 5732                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5733                        .and_then(|(buffer_snapshot, range)| {
 5734                            editor
 5735                                .buffer
 5736                                .read(cx)
 5737                                .buffer(buffer_snapshot.remote_id())
 5738                                .map(|buffer| (buffer, range.start.row))
 5739                        })?;
 5740                    let (_, code_actions) = editor
 5741                        .available_code_actions
 5742                        .clone()
 5743                        .and_then(|(location, code_actions)| {
 5744                            let snapshot = location.buffer.read(cx).snapshot();
 5745                            let point_range = location.range.to_point(&snapshot);
 5746                            let point_range = point_range.start.row..=point_range.end.row;
 5747                            if point_range.contains(&buffer_row) {
 5748                                Some((location, code_actions))
 5749                            } else {
 5750                                None
 5751                            }
 5752                        })
 5753                        .unzip();
 5754                    let buffer_id = buffer.read(cx).remote_id();
 5755                    let tasks = editor
 5756                        .tasks
 5757                        .get(&(buffer_id, buffer_row))
 5758                        .map(|t| Arc::new(t.to_owned()));
 5759                    if tasks.is_none() && code_actions.is_none() {
 5760                        return None;
 5761                    }
 5762
 5763                    editor.completion_tasks.clear();
 5764                    editor.discard_inline_completion(false, cx);
 5765                    let task_context =
 5766                        tasks
 5767                            .as_ref()
 5768                            .zip(editor.project.clone())
 5769                            .map(|(tasks, project)| {
 5770                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5771                            });
 5772
 5773                    Some(cx.spawn_in(window, async move |editor, cx| {
 5774                        let task_context = match task_context {
 5775                            Some(task_context) => task_context.await,
 5776                            None => None,
 5777                        };
 5778                        let resolved_tasks =
 5779                            tasks
 5780                                .zip(task_context.clone())
 5781                                .map(|(tasks, task_context)| ResolvedTasks {
 5782                                    templates: tasks.resolve(&task_context).collect(),
 5783                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5784                                        multibuffer_point.row,
 5785                                        tasks.column,
 5786                                    )),
 5787                                });
 5788                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5789                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5790                                maybe!({
 5791                                    let project = editor.project.as_ref()?;
 5792                                    let dap_store = project.read(cx).dap_store();
 5793                                    let mut scenarios = vec![];
 5794                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5795                                    let buffer = buffer.read(cx);
 5796                                    let language = buffer.language()?;
 5797                                    let file = buffer.file();
 5798                                    let debug_adapter =
 5799                                        language_settings(language.name().into(), file, cx)
 5800                                            .debuggers
 5801                                            .first()
 5802                                            .map(SharedString::from)
 5803                                            .or_else(|| {
 5804                                                language
 5805                                                    .config()
 5806                                                    .debuggers
 5807                                                    .first()
 5808                                                    .map(SharedString::from)
 5809                                            })?;
 5810
 5811                                    dap_store.update(cx, |dap_store, cx| {
 5812                                        for (_, task) in &resolved_tasks.templates {
 5813                                            if let Some(scenario) = dap_store
 5814                                                .debug_scenario_for_build_task(
 5815                                                    task.original_task().clone(),
 5816                                                    debug_adapter.clone().into(),
 5817                                                    task.display_label().to_owned().into(),
 5818                                                    cx,
 5819                                                )
 5820                                            {
 5821                                                scenarios.push(scenario);
 5822                                            }
 5823                                        }
 5824                                    });
 5825                                    Some(scenarios)
 5826                                })
 5827                                .unwrap_or_default()
 5828                            } else {
 5829                                vec![]
 5830                            }
 5831                        })?;
 5832                        let spawn_straight_away = quick_launch
 5833                            && resolved_tasks
 5834                                .as_ref()
 5835                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5836                            && code_actions
 5837                                .as_ref()
 5838                                .map_or(true, |actions| actions.is_empty())
 5839                            && debug_scenarios.is_empty();
 5840                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5841                            crate::hover_popover::hide_hover(editor, cx);
 5842                            *editor.context_menu.borrow_mut() =
 5843                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5844                                    buffer,
 5845                                    actions: CodeActionContents::new(
 5846                                        resolved_tasks,
 5847                                        code_actions,
 5848                                        debug_scenarios,
 5849                                        task_context.unwrap_or_default(),
 5850                                    ),
 5851                                    selected_item: Default::default(),
 5852                                    scroll_handle: UniformListScrollHandle::default(),
 5853                                    deployed_from,
 5854                                }));
 5855                            if spawn_straight_away {
 5856                                if let Some(task) = editor.confirm_code_action(
 5857                                    &ConfirmCodeAction { item_ix: Some(0) },
 5858                                    window,
 5859                                    cx,
 5860                                ) {
 5861                                    cx.notify();
 5862                                    return task;
 5863                                }
 5864                            }
 5865                            cx.notify();
 5866                            Task::ready(Ok(()))
 5867                        }) {
 5868                            task.await
 5869                        } else {
 5870                            Ok(())
 5871                        }
 5872                    }))
 5873                } else {
 5874                    Some(Task::ready(Ok(())))
 5875                }
 5876            })?;
 5877            if let Some(task) = spawned_test_task {
 5878                task.await?;
 5879            }
 5880
 5881            anyhow::Ok(())
 5882        })
 5883        .detach_and_log_err(cx);
 5884    }
 5885
 5886    pub fn confirm_code_action(
 5887        &mut self,
 5888        action: &ConfirmCodeAction,
 5889        window: &mut Window,
 5890        cx: &mut Context<Self>,
 5891    ) -> Option<Task<Result<()>>> {
 5892        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5893
 5894        let actions_menu =
 5895            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5896                menu
 5897            } else {
 5898                return None;
 5899            };
 5900
 5901        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5902        let action = actions_menu.actions.get(action_ix)?;
 5903        let title = action.label();
 5904        let buffer = actions_menu.buffer;
 5905        let workspace = self.workspace()?;
 5906
 5907        match action {
 5908            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5909                workspace.update(cx, |workspace, cx| {
 5910                    workspace.schedule_resolved_task(
 5911                        task_source_kind,
 5912                        resolved_task,
 5913                        false,
 5914                        window,
 5915                        cx,
 5916                    );
 5917
 5918                    Some(Task::ready(Ok(())))
 5919                })
 5920            }
 5921            CodeActionsItem::CodeAction {
 5922                excerpt_id,
 5923                action,
 5924                provider,
 5925            } => {
 5926                let apply_code_action =
 5927                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5928                let workspace = workspace.downgrade();
 5929                Some(cx.spawn_in(window, async move |editor, cx| {
 5930                    let project_transaction = apply_code_action.await?;
 5931                    Self::open_project_transaction(
 5932                        &editor,
 5933                        workspace,
 5934                        project_transaction,
 5935                        title,
 5936                        cx,
 5937                    )
 5938                    .await
 5939                }))
 5940            }
 5941            CodeActionsItem::DebugScenario(scenario) => {
 5942                let context = actions_menu.actions.context.clone();
 5943
 5944                workspace.update(cx, |workspace, cx| {
 5945                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5946                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5947                });
 5948                Some(Task::ready(Ok(())))
 5949            }
 5950        }
 5951    }
 5952
 5953    pub async fn open_project_transaction(
 5954        this: &WeakEntity<Editor>,
 5955        workspace: WeakEntity<Workspace>,
 5956        transaction: ProjectTransaction,
 5957        title: String,
 5958        cx: &mut AsyncWindowContext,
 5959    ) -> Result<()> {
 5960        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5961        cx.update(|_, cx| {
 5962            entries.sort_unstable_by_key(|(buffer, _)| {
 5963                buffer.read(cx).file().map(|f| f.path().clone())
 5964            });
 5965        })?;
 5966
 5967        // If the project transaction's edits are all contained within this editor, then
 5968        // avoid opening a new editor to display them.
 5969
 5970        if let Some((buffer, transaction)) = entries.first() {
 5971            if entries.len() == 1 {
 5972                let excerpt = this.update(cx, |editor, cx| {
 5973                    editor
 5974                        .buffer()
 5975                        .read(cx)
 5976                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5977                })?;
 5978                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5979                    if excerpted_buffer == *buffer {
 5980                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5981                            let excerpt_range = excerpt_range.to_offset(buffer);
 5982                            buffer
 5983                                .edited_ranges_for_transaction::<usize>(transaction)
 5984                                .all(|range| {
 5985                                    excerpt_range.start <= range.start
 5986                                        && excerpt_range.end >= range.end
 5987                                })
 5988                        })?;
 5989
 5990                        if all_edits_within_excerpt {
 5991                            return Ok(());
 5992                        }
 5993                    }
 5994                }
 5995            }
 5996        } else {
 5997            return Ok(());
 5998        }
 5999
 6000        let mut ranges_to_highlight = Vec::new();
 6001        let excerpt_buffer = cx.new(|cx| {
 6002            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6003            for (buffer_handle, transaction) in &entries {
 6004                let edited_ranges = buffer_handle
 6005                    .read(cx)
 6006                    .edited_ranges_for_transaction::<Point>(transaction)
 6007                    .collect::<Vec<_>>();
 6008                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6009                    PathKey::for_buffer(buffer_handle, cx),
 6010                    buffer_handle.clone(),
 6011                    edited_ranges,
 6012                    DEFAULT_MULTIBUFFER_CONTEXT,
 6013                    cx,
 6014                );
 6015
 6016                ranges_to_highlight.extend(ranges);
 6017            }
 6018            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6019            multibuffer
 6020        })?;
 6021
 6022        workspace.update_in(cx, |workspace, window, cx| {
 6023            let project = workspace.project().clone();
 6024            let editor =
 6025                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6026            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6027            editor.update(cx, |editor, cx| {
 6028                editor.highlight_background::<Self>(
 6029                    &ranges_to_highlight,
 6030                    |theme| theme.editor_highlighted_line_background,
 6031                    cx,
 6032                );
 6033            });
 6034        })?;
 6035
 6036        Ok(())
 6037    }
 6038
 6039    pub fn clear_code_action_providers(&mut self) {
 6040        self.code_action_providers.clear();
 6041        self.available_code_actions.take();
 6042    }
 6043
 6044    pub fn add_code_action_provider(
 6045        &mut self,
 6046        provider: Rc<dyn CodeActionProvider>,
 6047        window: &mut Window,
 6048        cx: &mut Context<Self>,
 6049    ) {
 6050        if self
 6051            .code_action_providers
 6052            .iter()
 6053            .any(|existing_provider| existing_provider.id() == provider.id())
 6054        {
 6055            return;
 6056        }
 6057
 6058        self.code_action_providers.push(provider);
 6059        self.refresh_code_actions(window, cx);
 6060    }
 6061
 6062    pub fn remove_code_action_provider(
 6063        &mut self,
 6064        id: Arc<str>,
 6065        window: &mut Window,
 6066        cx: &mut Context<Self>,
 6067    ) {
 6068        self.code_action_providers
 6069            .retain(|provider| provider.id() != id);
 6070        self.refresh_code_actions(window, cx);
 6071    }
 6072
 6073    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6074        !self.code_action_providers.is_empty()
 6075            && EditorSettings::get_global(cx).toolbar.code_actions
 6076    }
 6077
 6078    pub fn has_available_code_actions(&self) -> bool {
 6079        self.available_code_actions
 6080            .as_ref()
 6081            .is_some_and(|(_, actions)| !actions.is_empty())
 6082    }
 6083
 6084    fn render_inline_code_actions(
 6085        &self,
 6086        icon_size: ui::IconSize,
 6087        display_row: DisplayRow,
 6088        is_active: bool,
 6089        cx: &mut Context<Self>,
 6090    ) -> AnyElement {
 6091        let show_tooltip = !self.context_menu_visible();
 6092        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6093            .icon_size(icon_size)
 6094            .shape(ui::IconButtonShape::Square)
 6095            .style(ButtonStyle::Transparent)
 6096            .icon_color(ui::Color::Hidden)
 6097            .toggle_state(is_active)
 6098            .when(show_tooltip, |this| {
 6099                this.tooltip({
 6100                    let focus_handle = self.focus_handle.clone();
 6101                    move |window, cx| {
 6102                        Tooltip::for_action_in(
 6103                            "Toggle Code Actions",
 6104                            &ToggleCodeActions {
 6105                                deployed_from: None,
 6106                                quick_launch: false,
 6107                            },
 6108                            &focus_handle,
 6109                            window,
 6110                            cx,
 6111                        )
 6112                    }
 6113                })
 6114            })
 6115            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6116                window.focus(&editor.focus_handle(cx));
 6117                editor.toggle_code_actions(
 6118                    &crate::actions::ToggleCodeActions {
 6119                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6120                            display_row,
 6121                        )),
 6122                        quick_launch: false,
 6123                    },
 6124                    window,
 6125                    cx,
 6126                );
 6127            }))
 6128            .into_any_element()
 6129    }
 6130
 6131    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6132        &self.context_menu
 6133    }
 6134
 6135    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6136        let newest_selection = self.selections.newest_anchor().clone();
 6137        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6138        let buffer = self.buffer.read(cx);
 6139        if newest_selection.head().diff_base_anchor.is_some() {
 6140            return None;
 6141        }
 6142        let (start_buffer, start) =
 6143            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6144        let (end_buffer, end) =
 6145            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6146        if start_buffer != end_buffer {
 6147            return None;
 6148        }
 6149
 6150        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6151            cx.background_executor()
 6152                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6153                .await;
 6154
 6155            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6156                let providers = this.code_action_providers.clone();
 6157                let tasks = this
 6158                    .code_action_providers
 6159                    .iter()
 6160                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6161                    .collect::<Vec<_>>();
 6162                (providers, tasks)
 6163            })?;
 6164
 6165            let mut actions = Vec::new();
 6166            for (provider, provider_actions) in
 6167                providers.into_iter().zip(future::join_all(tasks).await)
 6168            {
 6169                if let Some(provider_actions) = provider_actions.log_err() {
 6170                    actions.extend(provider_actions.into_iter().map(|action| {
 6171                        AvailableCodeAction {
 6172                            excerpt_id: newest_selection.start.excerpt_id,
 6173                            action,
 6174                            provider: provider.clone(),
 6175                        }
 6176                    }));
 6177                }
 6178            }
 6179
 6180            this.update(cx, |this, cx| {
 6181                this.available_code_actions = if actions.is_empty() {
 6182                    None
 6183                } else {
 6184                    Some((
 6185                        Location {
 6186                            buffer: start_buffer,
 6187                            range: start..end,
 6188                        },
 6189                        actions.into(),
 6190                    ))
 6191                };
 6192                cx.notify();
 6193            })
 6194        }));
 6195        None
 6196    }
 6197
 6198    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6199        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6200            self.show_git_blame_inline = false;
 6201
 6202            self.show_git_blame_inline_delay_task =
 6203                Some(cx.spawn_in(window, async move |this, cx| {
 6204                    cx.background_executor().timer(delay).await;
 6205
 6206                    this.update(cx, |this, cx| {
 6207                        this.show_git_blame_inline = true;
 6208                        cx.notify();
 6209                    })
 6210                    .log_err();
 6211                }));
 6212        }
 6213    }
 6214
 6215    fn show_blame_popover(
 6216        &mut self,
 6217        blame_entry: &BlameEntry,
 6218        position: gpui::Point<Pixels>,
 6219        cx: &mut Context<Self>,
 6220    ) {
 6221        if let Some(state) = &mut self.inline_blame_popover {
 6222            state.hide_task.take();
 6223            cx.notify();
 6224        } else {
 6225            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6226            let show_task = cx.spawn(async move |editor, cx| {
 6227                cx.background_executor()
 6228                    .timer(std::time::Duration::from_millis(delay))
 6229                    .await;
 6230                editor
 6231                    .update(cx, |editor, cx| {
 6232                        if let Some(state) = &mut editor.inline_blame_popover {
 6233                            state.show_task = None;
 6234                            cx.notify();
 6235                        }
 6236                    })
 6237                    .ok();
 6238            });
 6239            let Some(blame) = self.blame.as_ref() else {
 6240                return;
 6241            };
 6242            let blame = blame.read(cx);
 6243            let details = blame.details_for_entry(&blame_entry);
 6244            let markdown = cx.new(|cx| {
 6245                Markdown::new(
 6246                    details
 6247                        .as_ref()
 6248                        .map(|message| message.message.clone())
 6249                        .unwrap_or_default(),
 6250                    None,
 6251                    None,
 6252                    cx,
 6253                )
 6254            });
 6255            self.inline_blame_popover = Some(InlineBlamePopover {
 6256                position,
 6257                show_task: Some(show_task),
 6258                hide_task: None,
 6259                popover_bounds: None,
 6260                popover_state: InlineBlamePopoverState {
 6261                    scroll_handle: ScrollHandle::new(),
 6262                    commit_message: details,
 6263                    markdown,
 6264                },
 6265            });
 6266        }
 6267    }
 6268
 6269    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6270        if let Some(state) = &mut self.inline_blame_popover {
 6271            if state.show_task.is_some() {
 6272                self.inline_blame_popover.take();
 6273                cx.notify();
 6274            } else {
 6275                let hide_task = cx.spawn(async move |editor, cx| {
 6276                    cx.background_executor()
 6277                        .timer(std::time::Duration::from_millis(100))
 6278                        .await;
 6279                    editor
 6280                        .update(cx, |editor, cx| {
 6281                            editor.inline_blame_popover.take();
 6282                            cx.notify();
 6283                        })
 6284                        .ok();
 6285                });
 6286                state.hide_task = Some(hide_task);
 6287            }
 6288        }
 6289    }
 6290
 6291    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6292        if self.pending_rename.is_some() {
 6293            return None;
 6294        }
 6295
 6296        let provider = self.semantics_provider.clone()?;
 6297        let buffer = self.buffer.read(cx);
 6298        let newest_selection = self.selections.newest_anchor().clone();
 6299        let cursor_position = newest_selection.head();
 6300        let (cursor_buffer, cursor_buffer_position) =
 6301            buffer.text_anchor_for_position(cursor_position, cx)?;
 6302        let (tail_buffer, tail_buffer_position) =
 6303            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6304        if cursor_buffer != tail_buffer {
 6305            return None;
 6306        }
 6307
 6308        let snapshot = cursor_buffer.read(cx).snapshot();
 6309        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6310        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6311        if start_word_range != end_word_range {
 6312            self.document_highlights_task.take();
 6313            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6314            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6315            return None;
 6316        }
 6317
 6318        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6319        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6320            cx.background_executor()
 6321                .timer(Duration::from_millis(debounce))
 6322                .await;
 6323
 6324            let highlights = if let Some(highlights) = cx
 6325                .update(|cx| {
 6326                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6327                })
 6328                .ok()
 6329                .flatten()
 6330            {
 6331                highlights.await.log_err()
 6332            } else {
 6333                None
 6334            };
 6335
 6336            if let Some(highlights) = highlights {
 6337                this.update(cx, |this, cx| {
 6338                    if this.pending_rename.is_some() {
 6339                        return;
 6340                    }
 6341
 6342                    let buffer_id = cursor_position.buffer_id;
 6343                    let buffer = this.buffer.read(cx);
 6344                    if !buffer
 6345                        .text_anchor_for_position(cursor_position, cx)
 6346                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6347                    {
 6348                        return;
 6349                    }
 6350
 6351                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6352                    let mut write_ranges = Vec::new();
 6353                    let mut read_ranges = Vec::new();
 6354                    for highlight in highlights {
 6355                        for (excerpt_id, excerpt_range) in
 6356                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6357                        {
 6358                            let start = highlight
 6359                                .range
 6360                                .start
 6361                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6362                            let end = highlight
 6363                                .range
 6364                                .end
 6365                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6366                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6367                                continue;
 6368                            }
 6369
 6370                            let range = Anchor {
 6371                                buffer_id,
 6372                                excerpt_id,
 6373                                text_anchor: start,
 6374                                diff_base_anchor: None,
 6375                            }..Anchor {
 6376                                buffer_id,
 6377                                excerpt_id,
 6378                                text_anchor: end,
 6379                                diff_base_anchor: None,
 6380                            };
 6381                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6382                                write_ranges.push(range);
 6383                            } else {
 6384                                read_ranges.push(range);
 6385                            }
 6386                        }
 6387                    }
 6388
 6389                    this.highlight_background::<DocumentHighlightRead>(
 6390                        &read_ranges,
 6391                        |theme| theme.editor_document_highlight_read_background,
 6392                        cx,
 6393                    );
 6394                    this.highlight_background::<DocumentHighlightWrite>(
 6395                        &write_ranges,
 6396                        |theme| theme.editor_document_highlight_write_background,
 6397                        cx,
 6398                    );
 6399                    cx.notify();
 6400                })
 6401                .log_err();
 6402            }
 6403        }));
 6404        None
 6405    }
 6406
 6407    fn prepare_highlight_query_from_selection(
 6408        &mut self,
 6409        cx: &mut Context<Editor>,
 6410    ) -> Option<(String, Range<Anchor>)> {
 6411        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6412            return None;
 6413        }
 6414        if !EditorSettings::get_global(cx).selection_highlight {
 6415            return None;
 6416        }
 6417        if self.selections.count() != 1 || self.selections.line_mode {
 6418            return None;
 6419        }
 6420        let selection = self.selections.newest::<Point>(cx);
 6421        if selection.is_empty() || selection.start.row != selection.end.row {
 6422            return None;
 6423        }
 6424        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6425        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6426        let query = multi_buffer_snapshot
 6427            .text_for_range(selection_anchor_range.clone())
 6428            .collect::<String>();
 6429        if query.trim().is_empty() {
 6430            return None;
 6431        }
 6432        Some((query, selection_anchor_range))
 6433    }
 6434
 6435    fn update_selection_occurrence_highlights(
 6436        &mut self,
 6437        query_text: String,
 6438        query_range: Range<Anchor>,
 6439        multi_buffer_range_to_query: Range<Point>,
 6440        use_debounce: bool,
 6441        window: &mut Window,
 6442        cx: &mut Context<Editor>,
 6443    ) -> Task<()> {
 6444        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6445        cx.spawn_in(window, async move |editor, cx| {
 6446            if use_debounce {
 6447                cx.background_executor()
 6448                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6449                    .await;
 6450            }
 6451            let match_task = cx.background_spawn(async move {
 6452                let buffer_ranges = multi_buffer_snapshot
 6453                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6454                    .into_iter()
 6455                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6456                let mut match_ranges = Vec::new();
 6457                let Ok(regex) = project::search::SearchQuery::text(
 6458                    query_text.clone(),
 6459                    false,
 6460                    false,
 6461                    false,
 6462                    Default::default(),
 6463                    Default::default(),
 6464                    false,
 6465                    None,
 6466                ) else {
 6467                    return Vec::default();
 6468                };
 6469                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6470                    match_ranges.extend(
 6471                        regex
 6472                            .search(&buffer_snapshot, Some(search_range.clone()))
 6473                            .await
 6474                            .into_iter()
 6475                            .filter_map(|match_range| {
 6476                                let match_start = buffer_snapshot
 6477                                    .anchor_after(search_range.start + match_range.start);
 6478                                let match_end = buffer_snapshot
 6479                                    .anchor_before(search_range.start + match_range.end);
 6480                                let match_anchor_range = Anchor::range_in_buffer(
 6481                                    excerpt_id,
 6482                                    buffer_snapshot.remote_id(),
 6483                                    match_start..match_end,
 6484                                );
 6485                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6486                            }),
 6487                    );
 6488                }
 6489                match_ranges
 6490            });
 6491            let match_ranges = match_task.await;
 6492            editor
 6493                .update_in(cx, |editor, _, cx| {
 6494                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6495                    if !match_ranges.is_empty() {
 6496                        editor.highlight_background::<SelectedTextHighlight>(
 6497                            &match_ranges,
 6498                            |theme| theme.editor_document_highlight_bracket_background,
 6499                            cx,
 6500                        )
 6501                    }
 6502                })
 6503                .log_err();
 6504        })
 6505    }
 6506
 6507    fn refresh_selected_text_highlights(
 6508        &mut self,
 6509        on_buffer_edit: bool,
 6510        window: &mut Window,
 6511        cx: &mut Context<Editor>,
 6512    ) {
 6513        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6514        else {
 6515            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6516            self.quick_selection_highlight_task.take();
 6517            self.debounced_selection_highlight_task.take();
 6518            return;
 6519        };
 6520        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6521        if on_buffer_edit
 6522            || self
 6523                .quick_selection_highlight_task
 6524                .as_ref()
 6525                .map_or(true, |(prev_anchor_range, _)| {
 6526                    prev_anchor_range != &query_range
 6527                })
 6528        {
 6529            let multi_buffer_visible_start = self
 6530                .scroll_manager
 6531                .anchor()
 6532                .anchor
 6533                .to_point(&multi_buffer_snapshot);
 6534            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6535                multi_buffer_visible_start
 6536                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6537                Bias::Left,
 6538            );
 6539            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6540            self.quick_selection_highlight_task = Some((
 6541                query_range.clone(),
 6542                self.update_selection_occurrence_highlights(
 6543                    query_text.clone(),
 6544                    query_range.clone(),
 6545                    multi_buffer_visible_range,
 6546                    false,
 6547                    window,
 6548                    cx,
 6549                ),
 6550            ));
 6551        }
 6552        if on_buffer_edit
 6553            || self
 6554                .debounced_selection_highlight_task
 6555                .as_ref()
 6556                .map_or(true, |(prev_anchor_range, _)| {
 6557                    prev_anchor_range != &query_range
 6558                })
 6559        {
 6560            let multi_buffer_start = multi_buffer_snapshot
 6561                .anchor_before(0)
 6562                .to_point(&multi_buffer_snapshot);
 6563            let multi_buffer_end = multi_buffer_snapshot
 6564                .anchor_after(multi_buffer_snapshot.len())
 6565                .to_point(&multi_buffer_snapshot);
 6566            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6567            self.debounced_selection_highlight_task = Some((
 6568                query_range.clone(),
 6569                self.update_selection_occurrence_highlights(
 6570                    query_text,
 6571                    query_range,
 6572                    multi_buffer_full_range,
 6573                    true,
 6574                    window,
 6575                    cx,
 6576                ),
 6577            ));
 6578        }
 6579    }
 6580
 6581    pub fn refresh_inline_completion(
 6582        &mut self,
 6583        debounce: bool,
 6584        user_requested: bool,
 6585        window: &mut Window,
 6586        cx: &mut Context<Self>,
 6587    ) -> Option<()> {
 6588        let provider = self.edit_prediction_provider()?;
 6589        let cursor = self.selections.newest_anchor().head();
 6590        let (buffer, cursor_buffer_position) =
 6591            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6592
 6593        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6594            self.discard_inline_completion(false, cx);
 6595            return None;
 6596        }
 6597
 6598        if !user_requested
 6599            && (!self.should_show_edit_predictions()
 6600                || !self.is_focused(window)
 6601                || buffer.read(cx).is_empty())
 6602        {
 6603            self.discard_inline_completion(false, cx);
 6604            return None;
 6605        }
 6606
 6607        self.update_visible_inline_completion(window, cx);
 6608        provider.refresh(
 6609            self.project.clone(),
 6610            buffer,
 6611            cursor_buffer_position,
 6612            debounce,
 6613            cx,
 6614        );
 6615        Some(())
 6616    }
 6617
 6618    fn show_edit_predictions_in_menu(&self) -> bool {
 6619        match self.edit_prediction_settings {
 6620            EditPredictionSettings::Disabled => false,
 6621            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6622        }
 6623    }
 6624
 6625    pub fn edit_predictions_enabled(&self) -> bool {
 6626        match self.edit_prediction_settings {
 6627            EditPredictionSettings::Disabled => false,
 6628            EditPredictionSettings::Enabled { .. } => true,
 6629        }
 6630    }
 6631
 6632    fn edit_prediction_requires_modifier(&self) -> bool {
 6633        match self.edit_prediction_settings {
 6634            EditPredictionSettings::Disabled => false,
 6635            EditPredictionSettings::Enabled {
 6636                preview_requires_modifier,
 6637                ..
 6638            } => preview_requires_modifier,
 6639        }
 6640    }
 6641
 6642    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6643        if self.edit_prediction_provider.is_none() {
 6644            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6645        } else {
 6646            let selection = self.selections.newest_anchor();
 6647            let cursor = selection.head();
 6648
 6649            if let Some((buffer, cursor_buffer_position)) =
 6650                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6651            {
 6652                self.edit_prediction_settings =
 6653                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6654            }
 6655        }
 6656    }
 6657
 6658    fn edit_prediction_settings_at_position(
 6659        &self,
 6660        buffer: &Entity<Buffer>,
 6661        buffer_position: language::Anchor,
 6662        cx: &App,
 6663    ) -> EditPredictionSettings {
 6664        if !self.mode.is_full()
 6665            || !self.show_inline_completions_override.unwrap_or(true)
 6666            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6667        {
 6668            return EditPredictionSettings::Disabled;
 6669        }
 6670
 6671        let buffer = buffer.read(cx);
 6672
 6673        let file = buffer.file();
 6674
 6675        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6676            return EditPredictionSettings::Disabled;
 6677        };
 6678
 6679        let by_provider = matches!(
 6680            self.menu_inline_completions_policy,
 6681            MenuInlineCompletionsPolicy::ByProvider
 6682        );
 6683
 6684        let show_in_menu = by_provider
 6685            && self
 6686                .edit_prediction_provider
 6687                .as_ref()
 6688                .map_or(false, |provider| {
 6689                    provider.provider.show_completions_in_menu()
 6690                });
 6691
 6692        let preview_requires_modifier =
 6693            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6694
 6695        EditPredictionSettings::Enabled {
 6696            show_in_menu,
 6697            preview_requires_modifier,
 6698        }
 6699    }
 6700
 6701    fn should_show_edit_predictions(&self) -> bool {
 6702        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6703    }
 6704
 6705    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6706        matches!(
 6707            self.edit_prediction_preview,
 6708            EditPredictionPreview::Active { .. }
 6709        )
 6710    }
 6711
 6712    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6713        let cursor = self.selections.newest_anchor().head();
 6714        if let Some((buffer, cursor_position)) =
 6715            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6716        {
 6717            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6718        } else {
 6719            false
 6720        }
 6721    }
 6722
 6723    pub fn supports_minimap(&self, cx: &App) -> bool {
 6724        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6725    }
 6726
 6727    fn edit_predictions_enabled_in_buffer(
 6728        &self,
 6729        buffer: &Entity<Buffer>,
 6730        buffer_position: language::Anchor,
 6731        cx: &App,
 6732    ) -> bool {
 6733        maybe!({
 6734            if self.read_only(cx) {
 6735                return Some(false);
 6736            }
 6737            let provider = self.edit_prediction_provider()?;
 6738            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6739                return Some(false);
 6740            }
 6741            let buffer = buffer.read(cx);
 6742            let Some(file) = buffer.file() else {
 6743                return Some(true);
 6744            };
 6745            let settings = all_language_settings(Some(file), cx);
 6746            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6747        })
 6748        .unwrap_or(false)
 6749    }
 6750
 6751    fn cycle_inline_completion(
 6752        &mut self,
 6753        direction: Direction,
 6754        window: &mut Window,
 6755        cx: &mut Context<Self>,
 6756    ) -> Option<()> {
 6757        let provider = self.edit_prediction_provider()?;
 6758        let cursor = self.selections.newest_anchor().head();
 6759        let (buffer, cursor_buffer_position) =
 6760            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6761        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6762            return None;
 6763        }
 6764
 6765        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6766        self.update_visible_inline_completion(window, cx);
 6767
 6768        Some(())
 6769    }
 6770
 6771    pub fn show_inline_completion(
 6772        &mut self,
 6773        _: &ShowEditPrediction,
 6774        window: &mut Window,
 6775        cx: &mut Context<Self>,
 6776    ) {
 6777        if !self.has_active_inline_completion() {
 6778            self.refresh_inline_completion(false, true, window, cx);
 6779            return;
 6780        }
 6781
 6782        self.update_visible_inline_completion(window, cx);
 6783    }
 6784
 6785    pub fn display_cursor_names(
 6786        &mut self,
 6787        _: &DisplayCursorNames,
 6788        window: &mut Window,
 6789        cx: &mut Context<Self>,
 6790    ) {
 6791        self.show_cursor_names(window, cx);
 6792    }
 6793
 6794    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6795        self.show_cursor_names = true;
 6796        cx.notify();
 6797        cx.spawn_in(window, async move |this, cx| {
 6798            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6799            this.update(cx, |this, cx| {
 6800                this.show_cursor_names = false;
 6801                cx.notify()
 6802            })
 6803            .ok()
 6804        })
 6805        .detach();
 6806    }
 6807
 6808    pub fn next_edit_prediction(
 6809        &mut self,
 6810        _: &NextEditPrediction,
 6811        window: &mut Window,
 6812        cx: &mut Context<Self>,
 6813    ) {
 6814        if self.has_active_inline_completion() {
 6815            self.cycle_inline_completion(Direction::Next, window, cx);
 6816        } else {
 6817            let is_copilot_disabled = self
 6818                .refresh_inline_completion(false, true, window, cx)
 6819                .is_none();
 6820            if is_copilot_disabled {
 6821                cx.propagate();
 6822            }
 6823        }
 6824    }
 6825
 6826    pub fn previous_edit_prediction(
 6827        &mut self,
 6828        _: &PreviousEditPrediction,
 6829        window: &mut Window,
 6830        cx: &mut Context<Self>,
 6831    ) {
 6832        if self.has_active_inline_completion() {
 6833            self.cycle_inline_completion(Direction::Prev, window, cx);
 6834        } else {
 6835            let is_copilot_disabled = self
 6836                .refresh_inline_completion(false, true, window, cx)
 6837                .is_none();
 6838            if is_copilot_disabled {
 6839                cx.propagate();
 6840            }
 6841        }
 6842    }
 6843
 6844    pub fn accept_edit_prediction(
 6845        &mut self,
 6846        _: &AcceptEditPrediction,
 6847        window: &mut Window,
 6848        cx: &mut Context<Self>,
 6849    ) {
 6850        if self.show_edit_predictions_in_menu() {
 6851            self.hide_context_menu(window, cx);
 6852        }
 6853
 6854        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6855            return;
 6856        };
 6857
 6858        self.report_inline_completion_event(
 6859            active_inline_completion.completion_id.clone(),
 6860            true,
 6861            cx,
 6862        );
 6863
 6864        match &active_inline_completion.completion {
 6865            InlineCompletion::Move { target, .. } => {
 6866                let target = *target;
 6867
 6868                if let Some(position_map) = &self.last_position_map {
 6869                    if position_map
 6870                        .visible_row_range
 6871                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6872                        || !self.edit_prediction_requires_modifier()
 6873                    {
 6874                        self.unfold_ranges(&[target..target], true, false, cx);
 6875                        // Note that this is also done in vim's handler of the Tab action.
 6876                        self.change_selections(
 6877                            Some(Autoscroll::newest()),
 6878                            window,
 6879                            cx,
 6880                            |selections| {
 6881                                selections.select_anchor_ranges([target..target]);
 6882                            },
 6883                        );
 6884                        self.clear_row_highlights::<EditPredictionPreview>();
 6885
 6886                        self.edit_prediction_preview
 6887                            .set_previous_scroll_position(None);
 6888                    } else {
 6889                        self.edit_prediction_preview
 6890                            .set_previous_scroll_position(Some(
 6891                                position_map.snapshot.scroll_anchor,
 6892                            ));
 6893
 6894                        self.highlight_rows::<EditPredictionPreview>(
 6895                            target..target,
 6896                            cx.theme().colors().editor_highlighted_line_background,
 6897                            RowHighlightOptions {
 6898                                autoscroll: true,
 6899                                ..Default::default()
 6900                            },
 6901                            cx,
 6902                        );
 6903                        self.request_autoscroll(Autoscroll::fit(), cx);
 6904                    }
 6905                }
 6906            }
 6907            InlineCompletion::Edit { edits, .. } => {
 6908                if let Some(provider) = self.edit_prediction_provider() {
 6909                    provider.accept(cx);
 6910                }
 6911
 6912                // Store the transaction ID and selections before applying the edit
 6913                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6914
 6915                let snapshot = self.buffer.read(cx).snapshot(cx);
 6916                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6917
 6918                self.buffer.update(cx, |buffer, cx| {
 6919                    buffer.edit(edits.iter().cloned(), None, cx)
 6920                });
 6921
 6922                self.change_selections(None, window, cx, |s| {
 6923                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6924                });
 6925
 6926                let selections = self.selections.disjoint_anchors();
 6927                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6928                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6929                    if has_new_transaction {
 6930                        self.selection_history
 6931                            .insert_transaction(transaction_id_now, selections);
 6932                    }
 6933                }
 6934
 6935                self.update_visible_inline_completion(window, cx);
 6936                if self.active_inline_completion.is_none() {
 6937                    self.refresh_inline_completion(true, true, window, cx);
 6938                }
 6939
 6940                cx.notify();
 6941            }
 6942        }
 6943
 6944        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6945    }
 6946
 6947    pub fn accept_partial_inline_completion(
 6948        &mut self,
 6949        _: &AcceptPartialEditPrediction,
 6950        window: &mut Window,
 6951        cx: &mut Context<Self>,
 6952    ) {
 6953        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6954            return;
 6955        };
 6956        if self.selections.count() != 1 {
 6957            return;
 6958        }
 6959
 6960        self.report_inline_completion_event(
 6961            active_inline_completion.completion_id.clone(),
 6962            true,
 6963            cx,
 6964        );
 6965
 6966        match &active_inline_completion.completion {
 6967            InlineCompletion::Move { target, .. } => {
 6968                let target = *target;
 6969                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6970                    selections.select_anchor_ranges([target..target]);
 6971                });
 6972            }
 6973            InlineCompletion::Edit { edits, .. } => {
 6974                // Find an insertion that starts at the cursor position.
 6975                let snapshot = self.buffer.read(cx).snapshot(cx);
 6976                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6977                let insertion = edits.iter().find_map(|(range, text)| {
 6978                    let range = range.to_offset(&snapshot);
 6979                    if range.is_empty() && range.start == cursor_offset {
 6980                        Some(text)
 6981                    } else {
 6982                        None
 6983                    }
 6984                });
 6985
 6986                if let Some(text) = insertion {
 6987                    let mut partial_completion = text
 6988                        .chars()
 6989                        .by_ref()
 6990                        .take_while(|c| c.is_alphabetic())
 6991                        .collect::<String>();
 6992                    if partial_completion.is_empty() {
 6993                        partial_completion = text
 6994                            .chars()
 6995                            .by_ref()
 6996                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6997                            .collect::<String>();
 6998                    }
 6999
 7000                    cx.emit(EditorEvent::InputHandled {
 7001                        utf16_range_to_replace: None,
 7002                        text: partial_completion.clone().into(),
 7003                    });
 7004
 7005                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7006
 7007                    self.refresh_inline_completion(true, true, window, cx);
 7008                    cx.notify();
 7009                } else {
 7010                    self.accept_edit_prediction(&Default::default(), window, cx);
 7011                }
 7012            }
 7013        }
 7014    }
 7015
 7016    fn discard_inline_completion(
 7017        &mut self,
 7018        should_report_inline_completion_event: bool,
 7019        cx: &mut Context<Self>,
 7020    ) -> bool {
 7021        if should_report_inline_completion_event {
 7022            let completion_id = self
 7023                .active_inline_completion
 7024                .as_ref()
 7025                .and_then(|active_completion| active_completion.completion_id.clone());
 7026
 7027            self.report_inline_completion_event(completion_id, false, cx);
 7028        }
 7029
 7030        if let Some(provider) = self.edit_prediction_provider() {
 7031            provider.discard(cx);
 7032        }
 7033
 7034        self.take_active_inline_completion(cx)
 7035    }
 7036
 7037    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7038        let Some(provider) = self.edit_prediction_provider() else {
 7039            return;
 7040        };
 7041
 7042        let Some((_, buffer, _)) = self
 7043            .buffer
 7044            .read(cx)
 7045            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7046        else {
 7047            return;
 7048        };
 7049
 7050        let extension = buffer
 7051            .read(cx)
 7052            .file()
 7053            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7054
 7055        let event_type = match accepted {
 7056            true => "Edit Prediction Accepted",
 7057            false => "Edit Prediction Discarded",
 7058        };
 7059        telemetry::event!(
 7060            event_type,
 7061            provider = provider.name(),
 7062            prediction_id = id,
 7063            suggestion_accepted = accepted,
 7064            file_extension = extension,
 7065        );
 7066    }
 7067
 7068    pub fn has_active_inline_completion(&self) -> bool {
 7069        self.active_inline_completion.is_some()
 7070    }
 7071
 7072    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7073        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7074            return false;
 7075        };
 7076
 7077        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7078        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7079        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7080        true
 7081    }
 7082
 7083    /// Returns true when we're displaying the edit prediction popover below the cursor
 7084    /// like we are not previewing and the LSP autocomplete menu is visible
 7085    /// or we are in `when_holding_modifier` mode.
 7086    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7087        if self.edit_prediction_preview_is_active()
 7088            || !self.show_edit_predictions_in_menu()
 7089            || !self.edit_predictions_enabled()
 7090        {
 7091            return false;
 7092        }
 7093
 7094        if self.has_visible_completions_menu() {
 7095            return true;
 7096        }
 7097
 7098        has_completion && self.edit_prediction_requires_modifier()
 7099    }
 7100
 7101    fn handle_modifiers_changed(
 7102        &mut self,
 7103        modifiers: Modifiers,
 7104        position_map: &PositionMap,
 7105        window: &mut Window,
 7106        cx: &mut Context<Self>,
 7107    ) {
 7108        if self.show_edit_predictions_in_menu() {
 7109            self.update_edit_prediction_preview(&modifiers, window, cx);
 7110        }
 7111
 7112        self.update_selection_mode(&modifiers, position_map, window, cx);
 7113
 7114        let mouse_position = window.mouse_position();
 7115        if !position_map.text_hitbox.is_hovered(window) {
 7116            return;
 7117        }
 7118
 7119        self.update_hovered_link(
 7120            position_map.point_for_position(mouse_position),
 7121            &position_map.snapshot,
 7122            modifiers,
 7123            window,
 7124            cx,
 7125        )
 7126    }
 7127
 7128    fn multi_cursor_modifier(
 7129        cursor_event: bool,
 7130        modifiers: &Modifiers,
 7131        cx: &mut Context<Self>,
 7132    ) -> bool {
 7133        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7134        if cursor_event {
 7135            match multi_cursor_setting {
 7136                MultiCursorModifier::Alt => modifiers.alt,
 7137                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7138            }
 7139        } else {
 7140            match multi_cursor_setting {
 7141                MultiCursorModifier::Alt => modifiers.secondary(),
 7142                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7143            }
 7144        }
 7145    }
 7146
 7147    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7148        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7149    }
 7150
 7151    fn update_selection_mode(
 7152        &mut self,
 7153        modifiers: &Modifiers,
 7154        position_map: &PositionMap,
 7155        window: &mut Window,
 7156        cx: &mut Context<Self>,
 7157    ) {
 7158        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7159        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7160            || self.selections.pending.is_none()
 7161        {
 7162            return;
 7163        }
 7164
 7165        let mouse_position = window.mouse_position();
 7166        let point_for_position = position_map.point_for_position(mouse_position);
 7167        let position = point_for_position.previous_valid;
 7168
 7169        self.select(
 7170            SelectPhase::BeginColumnar {
 7171                position,
 7172                reset: false,
 7173                goal_column: point_for_position.exact_unclipped.column(),
 7174            },
 7175            window,
 7176            cx,
 7177        );
 7178    }
 7179
 7180    fn update_edit_prediction_preview(
 7181        &mut self,
 7182        modifiers: &Modifiers,
 7183        window: &mut Window,
 7184        cx: &mut Context<Self>,
 7185    ) {
 7186        let mut modifiers_held = false;
 7187        if let Some(accept_keystroke) = self
 7188            .accept_edit_prediction_keybind(false, window, cx)
 7189            .keystroke()
 7190        {
 7191            modifiers_held = modifiers_held
 7192                || (&accept_keystroke.modifiers == modifiers
 7193                    && accept_keystroke.modifiers.modified());
 7194        };
 7195        if let Some(accept_partial_keystroke) = self
 7196            .accept_edit_prediction_keybind(true, window, cx)
 7197            .keystroke()
 7198        {
 7199            modifiers_held = modifiers_held
 7200                || (&accept_partial_keystroke.modifiers == modifiers
 7201                    && accept_partial_keystroke.modifiers.modified());
 7202        }
 7203
 7204        if modifiers_held {
 7205            if matches!(
 7206                self.edit_prediction_preview,
 7207                EditPredictionPreview::Inactive { .. }
 7208            ) {
 7209                self.edit_prediction_preview = EditPredictionPreview::Active {
 7210                    previous_scroll_position: None,
 7211                    since: Instant::now(),
 7212                };
 7213
 7214                self.update_visible_inline_completion(window, cx);
 7215                cx.notify();
 7216            }
 7217        } else if let EditPredictionPreview::Active {
 7218            previous_scroll_position,
 7219            since,
 7220        } = self.edit_prediction_preview
 7221        {
 7222            if let (Some(previous_scroll_position), Some(position_map)) =
 7223                (previous_scroll_position, self.last_position_map.as_ref())
 7224            {
 7225                self.set_scroll_position(
 7226                    previous_scroll_position
 7227                        .scroll_position(&position_map.snapshot.display_snapshot),
 7228                    window,
 7229                    cx,
 7230                );
 7231            }
 7232
 7233            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7234                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7235            };
 7236            self.clear_row_highlights::<EditPredictionPreview>();
 7237            self.update_visible_inline_completion(window, cx);
 7238            cx.notify();
 7239        }
 7240    }
 7241
 7242    fn update_visible_inline_completion(
 7243        &mut self,
 7244        _window: &mut Window,
 7245        cx: &mut Context<Self>,
 7246    ) -> Option<()> {
 7247        let selection = self.selections.newest_anchor();
 7248        let cursor = selection.head();
 7249        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7250        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7251        let excerpt_id = cursor.excerpt_id;
 7252
 7253        let show_in_menu = self.show_edit_predictions_in_menu();
 7254        let completions_menu_has_precedence = !show_in_menu
 7255            && (self.context_menu.borrow().is_some()
 7256                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7257
 7258        if completions_menu_has_precedence
 7259            || !offset_selection.is_empty()
 7260            || self
 7261                .active_inline_completion
 7262                .as_ref()
 7263                .map_or(false, |completion| {
 7264                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7265                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7266                    !invalidation_range.contains(&offset_selection.head())
 7267                })
 7268        {
 7269            self.discard_inline_completion(false, cx);
 7270            return None;
 7271        }
 7272
 7273        self.take_active_inline_completion(cx);
 7274        let Some(provider) = self.edit_prediction_provider() else {
 7275            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7276            return None;
 7277        };
 7278
 7279        let (buffer, cursor_buffer_position) =
 7280            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7281
 7282        self.edit_prediction_settings =
 7283            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7284
 7285        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7286
 7287        if self.edit_prediction_indent_conflict {
 7288            let cursor_point = cursor.to_point(&multibuffer);
 7289
 7290            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7291
 7292            if let Some((_, indent)) = indents.iter().next() {
 7293                if indent.len == cursor_point.column {
 7294                    self.edit_prediction_indent_conflict = false;
 7295                }
 7296            }
 7297        }
 7298
 7299        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7300        let edits = inline_completion
 7301            .edits
 7302            .into_iter()
 7303            .flat_map(|(range, new_text)| {
 7304                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7305                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7306                Some((start..end, new_text))
 7307            })
 7308            .collect::<Vec<_>>();
 7309        if edits.is_empty() {
 7310            return None;
 7311        }
 7312
 7313        let first_edit_start = edits.first().unwrap().0.start;
 7314        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7315        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7316
 7317        let last_edit_end = edits.last().unwrap().0.end;
 7318        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7319        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7320
 7321        let cursor_row = cursor.to_point(&multibuffer).row;
 7322
 7323        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7324
 7325        let mut inlay_ids = Vec::new();
 7326        let invalidation_row_range;
 7327        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7328            Some(cursor_row..edit_end_row)
 7329        } else if cursor_row > edit_end_row {
 7330            Some(edit_start_row..cursor_row)
 7331        } else {
 7332            None
 7333        };
 7334        let is_move =
 7335            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7336        let completion = if is_move {
 7337            invalidation_row_range =
 7338                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7339            let target = first_edit_start;
 7340            InlineCompletion::Move { target, snapshot }
 7341        } else {
 7342            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7343                && !self.inline_completions_hidden_for_vim_mode;
 7344
 7345            if show_completions_in_buffer {
 7346                if edits
 7347                    .iter()
 7348                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7349                {
 7350                    let mut inlays = Vec::new();
 7351                    for (range, new_text) in &edits {
 7352                        let inlay = Inlay::inline_completion(
 7353                            post_inc(&mut self.next_inlay_id),
 7354                            range.start,
 7355                            new_text.as_str(),
 7356                        );
 7357                        inlay_ids.push(inlay.id);
 7358                        inlays.push(inlay);
 7359                    }
 7360
 7361                    self.splice_inlays(&[], inlays, cx);
 7362                } else {
 7363                    let background_color = cx.theme().status().deleted_background;
 7364                    self.highlight_text::<InlineCompletionHighlight>(
 7365                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7366                        HighlightStyle {
 7367                            background_color: Some(background_color),
 7368                            ..Default::default()
 7369                        },
 7370                        cx,
 7371                    );
 7372                }
 7373            }
 7374
 7375            invalidation_row_range = edit_start_row..edit_end_row;
 7376
 7377            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7378                if provider.show_tab_accept_marker() {
 7379                    EditDisplayMode::TabAccept
 7380                } else {
 7381                    EditDisplayMode::Inline
 7382                }
 7383            } else {
 7384                EditDisplayMode::DiffPopover
 7385            };
 7386
 7387            InlineCompletion::Edit {
 7388                edits,
 7389                edit_preview: inline_completion.edit_preview,
 7390                display_mode,
 7391                snapshot,
 7392            }
 7393        };
 7394
 7395        let invalidation_range = multibuffer
 7396            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7397            ..multibuffer.anchor_after(Point::new(
 7398                invalidation_row_range.end,
 7399                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7400            ));
 7401
 7402        self.stale_inline_completion_in_menu = None;
 7403        self.active_inline_completion = Some(InlineCompletionState {
 7404            inlay_ids,
 7405            completion,
 7406            completion_id: inline_completion.id,
 7407            invalidation_range,
 7408        });
 7409
 7410        cx.notify();
 7411
 7412        Some(())
 7413    }
 7414
 7415    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7416        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7417    }
 7418
 7419    fn clear_tasks(&mut self) {
 7420        self.tasks.clear()
 7421    }
 7422
 7423    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7424        if self.tasks.insert(key, value).is_some() {
 7425            // This case should hopefully be rare, but just in case...
 7426            log::error!(
 7427                "multiple different run targets found on a single line, only the last target will be rendered"
 7428            )
 7429        }
 7430    }
 7431
 7432    /// Get all display points of breakpoints that will be rendered within editor
 7433    ///
 7434    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7435    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7436    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7437    fn active_breakpoints(
 7438        &self,
 7439        range: Range<DisplayRow>,
 7440        window: &mut Window,
 7441        cx: &mut Context<Self>,
 7442    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7443        let mut breakpoint_display_points = HashMap::default();
 7444
 7445        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7446            return breakpoint_display_points;
 7447        };
 7448
 7449        let snapshot = self.snapshot(window, cx);
 7450
 7451        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7452        let Some(project) = self.project.as_ref() else {
 7453            return breakpoint_display_points;
 7454        };
 7455
 7456        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7457            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7458
 7459        for (buffer_snapshot, range, excerpt_id) in
 7460            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7461        {
 7462            let Some(buffer) = project
 7463                .read(cx)
 7464                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7465            else {
 7466                continue;
 7467            };
 7468            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7469                &buffer,
 7470                Some(
 7471                    buffer_snapshot.anchor_before(range.start)
 7472                        ..buffer_snapshot.anchor_after(range.end),
 7473                ),
 7474                buffer_snapshot,
 7475                cx,
 7476            );
 7477            for (breakpoint, state) in breakpoints {
 7478                let multi_buffer_anchor =
 7479                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7480                let position = multi_buffer_anchor
 7481                    .to_point(&multi_buffer_snapshot)
 7482                    .to_display_point(&snapshot);
 7483
 7484                breakpoint_display_points.insert(
 7485                    position.row(),
 7486                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7487                );
 7488            }
 7489        }
 7490
 7491        breakpoint_display_points
 7492    }
 7493
 7494    fn breakpoint_context_menu(
 7495        &self,
 7496        anchor: Anchor,
 7497        window: &mut Window,
 7498        cx: &mut Context<Self>,
 7499    ) -> Entity<ui::ContextMenu> {
 7500        let weak_editor = cx.weak_entity();
 7501        let focus_handle = self.focus_handle(cx);
 7502
 7503        let row = self
 7504            .buffer
 7505            .read(cx)
 7506            .snapshot(cx)
 7507            .summary_for_anchor::<Point>(&anchor)
 7508            .row;
 7509
 7510        let breakpoint = self
 7511            .breakpoint_at_row(row, window, cx)
 7512            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7513
 7514        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7515            "Edit Log Breakpoint"
 7516        } else {
 7517            "Set Log Breakpoint"
 7518        };
 7519
 7520        let condition_breakpoint_msg = if breakpoint
 7521            .as_ref()
 7522            .is_some_and(|bp| bp.1.condition.is_some())
 7523        {
 7524            "Edit Condition Breakpoint"
 7525        } else {
 7526            "Set Condition Breakpoint"
 7527        };
 7528
 7529        let hit_condition_breakpoint_msg = if breakpoint
 7530            .as_ref()
 7531            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7532        {
 7533            "Edit Hit Condition Breakpoint"
 7534        } else {
 7535            "Set Hit Condition Breakpoint"
 7536        };
 7537
 7538        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7539            "Unset Breakpoint"
 7540        } else {
 7541            "Set Breakpoint"
 7542        };
 7543
 7544        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7545
 7546        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7547            BreakpointState::Enabled => Some("Disable"),
 7548            BreakpointState::Disabled => Some("Enable"),
 7549        });
 7550
 7551        let (anchor, breakpoint) =
 7552            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7553
 7554        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7555            menu.on_blur_subscription(Subscription::new(|| {}))
 7556                .context(focus_handle)
 7557                .when(run_to_cursor, |this| {
 7558                    let weak_editor = weak_editor.clone();
 7559                    this.entry("Run to cursor", None, move |window, cx| {
 7560                        weak_editor
 7561                            .update(cx, |editor, cx| {
 7562                                editor.change_selections(None, window, cx, |s| {
 7563                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7564                                });
 7565                            })
 7566                            .ok();
 7567
 7568                        window.dispatch_action(Box::new(RunToCursor), cx);
 7569                    })
 7570                    .separator()
 7571                })
 7572                .when_some(toggle_state_msg, |this, msg| {
 7573                    this.entry(msg, None, {
 7574                        let weak_editor = weak_editor.clone();
 7575                        let breakpoint = breakpoint.clone();
 7576                        move |_window, cx| {
 7577                            weak_editor
 7578                                .update(cx, |this, cx| {
 7579                                    this.edit_breakpoint_at_anchor(
 7580                                        anchor,
 7581                                        breakpoint.as_ref().clone(),
 7582                                        BreakpointEditAction::InvertState,
 7583                                        cx,
 7584                                    );
 7585                                })
 7586                                .log_err();
 7587                        }
 7588                    })
 7589                })
 7590                .entry(set_breakpoint_msg, None, {
 7591                    let weak_editor = weak_editor.clone();
 7592                    let breakpoint = breakpoint.clone();
 7593                    move |_window, cx| {
 7594                        weak_editor
 7595                            .update(cx, |this, cx| {
 7596                                this.edit_breakpoint_at_anchor(
 7597                                    anchor,
 7598                                    breakpoint.as_ref().clone(),
 7599                                    BreakpointEditAction::Toggle,
 7600                                    cx,
 7601                                );
 7602                            })
 7603                            .log_err();
 7604                    }
 7605                })
 7606                .entry(log_breakpoint_msg, None, {
 7607                    let breakpoint = breakpoint.clone();
 7608                    let weak_editor = weak_editor.clone();
 7609                    move |window, cx| {
 7610                        weak_editor
 7611                            .update(cx, |this, cx| {
 7612                                this.add_edit_breakpoint_block(
 7613                                    anchor,
 7614                                    breakpoint.as_ref(),
 7615                                    BreakpointPromptEditAction::Log,
 7616                                    window,
 7617                                    cx,
 7618                                );
 7619                            })
 7620                            .log_err();
 7621                    }
 7622                })
 7623                .entry(condition_breakpoint_msg, None, {
 7624                    let breakpoint = breakpoint.clone();
 7625                    let weak_editor = weak_editor.clone();
 7626                    move |window, cx| {
 7627                        weak_editor
 7628                            .update(cx, |this, cx| {
 7629                                this.add_edit_breakpoint_block(
 7630                                    anchor,
 7631                                    breakpoint.as_ref(),
 7632                                    BreakpointPromptEditAction::Condition,
 7633                                    window,
 7634                                    cx,
 7635                                );
 7636                            })
 7637                            .log_err();
 7638                    }
 7639                })
 7640                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7641                    weak_editor
 7642                        .update(cx, |this, cx| {
 7643                            this.add_edit_breakpoint_block(
 7644                                anchor,
 7645                                breakpoint.as_ref(),
 7646                                BreakpointPromptEditAction::HitCondition,
 7647                                window,
 7648                                cx,
 7649                            );
 7650                        })
 7651                        .log_err();
 7652                })
 7653        })
 7654    }
 7655
 7656    fn render_breakpoint(
 7657        &self,
 7658        position: Anchor,
 7659        row: DisplayRow,
 7660        breakpoint: &Breakpoint,
 7661        state: Option<BreakpointSessionState>,
 7662        cx: &mut Context<Self>,
 7663    ) -> IconButton {
 7664        let is_rejected = state.is_some_and(|s| !s.verified);
 7665        // Is it a breakpoint that shows up when hovering over gutter?
 7666        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7667            (false, false),
 7668            |PhantomBreakpointIndicator {
 7669                 is_active,
 7670                 display_row,
 7671                 collides_with_existing_breakpoint,
 7672             }| {
 7673                (
 7674                    is_active && display_row == row,
 7675                    collides_with_existing_breakpoint,
 7676                )
 7677            },
 7678        );
 7679
 7680        let (color, icon) = {
 7681            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7682                (false, false) => ui::IconName::DebugBreakpoint,
 7683                (true, false) => ui::IconName::DebugLogBreakpoint,
 7684                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7685                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7686            };
 7687
 7688            let color = if is_phantom {
 7689                Color::Hint
 7690            } else if is_rejected {
 7691                Color::Disabled
 7692            } else {
 7693                Color::Debugger
 7694            };
 7695
 7696            (color, icon)
 7697        };
 7698
 7699        let breakpoint = Arc::from(breakpoint.clone());
 7700
 7701        let alt_as_text = gpui::Keystroke {
 7702            modifiers: Modifiers::secondary_key(),
 7703            ..Default::default()
 7704        };
 7705        let primary_action_text = if breakpoint.is_disabled() {
 7706            "Enable breakpoint"
 7707        } else if is_phantom && !collides_with_existing {
 7708            "Set breakpoint"
 7709        } else {
 7710            "Unset breakpoint"
 7711        };
 7712        let focus_handle = self.focus_handle.clone();
 7713
 7714        let meta = if is_rejected {
 7715            SharedString::from("No executable code is associated with this line.")
 7716        } else if collides_with_existing && !breakpoint.is_disabled() {
 7717            SharedString::from(format!(
 7718                "{alt_as_text}-click to disable,\nright-click for more options."
 7719            ))
 7720        } else {
 7721            SharedString::from("Right-click for more options.")
 7722        };
 7723        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7724            .icon_size(IconSize::XSmall)
 7725            .size(ui::ButtonSize::None)
 7726            .when(is_rejected, |this| {
 7727                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7728            })
 7729            .icon_color(color)
 7730            .style(ButtonStyle::Transparent)
 7731            .on_click(cx.listener({
 7732                let breakpoint = breakpoint.clone();
 7733
 7734                move |editor, event: &ClickEvent, window, cx| {
 7735                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7736                        BreakpointEditAction::InvertState
 7737                    } else {
 7738                        BreakpointEditAction::Toggle
 7739                    };
 7740
 7741                    window.focus(&editor.focus_handle(cx));
 7742                    editor.edit_breakpoint_at_anchor(
 7743                        position,
 7744                        breakpoint.as_ref().clone(),
 7745                        edit_action,
 7746                        cx,
 7747                    );
 7748                }
 7749            }))
 7750            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7751                editor.set_breakpoint_context_menu(
 7752                    row,
 7753                    Some(position),
 7754                    event.down.position,
 7755                    window,
 7756                    cx,
 7757                );
 7758            }))
 7759            .tooltip(move |window, cx| {
 7760                Tooltip::with_meta_in(
 7761                    primary_action_text,
 7762                    Some(&ToggleBreakpoint),
 7763                    meta.clone(),
 7764                    &focus_handle,
 7765                    window,
 7766                    cx,
 7767                )
 7768            })
 7769    }
 7770
 7771    fn build_tasks_context(
 7772        project: &Entity<Project>,
 7773        buffer: &Entity<Buffer>,
 7774        buffer_row: u32,
 7775        tasks: &Arc<RunnableTasks>,
 7776        cx: &mut Context<Self>,
 7777    ) -> Task<Option<task::TaskContext>> {
 7778        let position = Point::new(buffer_row, tasks.column);
 7779        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7780        let location = Location {
 7781            buffer: buffer.clone(),
 7782            range: range_start..range_start,
 7783        };
 7784        // Fill in the environmental variables from the tree-sitter captures
 7785        let mut captured_task_variables = TaskVariables::default();
 7786        for (capture_name, value) in tasks.extra_variables.clone() {
 7787            captured_task_variables.insert(
 7788                task::VariableName::Custom(capture_name.into()),
 7789                value.clone(),
 7790            );
 7791        }
 7792        project.update(cx, |project, cx| {
 7793            project.task_store().update(cx, |task_store, cx| {
 7794                task_store.task_context_for_location(captured_task_variables, location, cx)
 7795            })
 7796        })
 7797    }
 7798
 7799    pub fn spawn_nearest_task(
 7800        &mut self,
 7801        action: &SpawnNearestTask,
 7802        window: &mut Window,
 7803        cx: &mut Context<Self>,
 7804    ) {
 7805        let Some((workspace, _)) = self.workspace.clone() else {
 7806            return;
 7807        };
 7808        let Some(project) = self.project.clone() else {
 7809            return;
 7810        };
 7811
 7812        // Try to find a closest, enclosing node using tree-sitter that has a
 7813        // task
 7814        let Some((buffer, buffer_row, tasks)) = self
 7815            .find_enclosing_node_task(cx)
 7816            // Or find the task that's closest in row-distance.
 7817            .or_else(|| self.find_closest_task(cx))
 7818        else {
 7819            return;
 7820        };
 7821
 7822        let reveal_strategy = action.reveal;
 7823        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7824        cx.spawn_in(window, async move |_, cx| {
 7825            let context = task_context.await?;
 7826            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7827
 7828            let resolved = &mut resolved_task.resolved;
 7829            resolved.reveal = reveal_strategy;
 7830
 7831            workspace
 7832                .update_in(cx, |workspace, window, cx| {
 7833                    workspace.schedule_resolved_task(
 7834                        task_source_kind,
 7835                        resolved_task,
 7836                        false,
 7837                        window,
 7838                        cx,
 7839                    );
 7840                })
 7841                .ok()
 7842        })
 7843        .detach();
 7844    }
 7845
 7846    fn find_closest_task(
 7847        &mut self,
 7848        cx: &mut Context<Self>,
 7849    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7850        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7851
 7852        let ((buffer_id, row), tasks) = self
 7853            .tasks
 7854            .iter()
 7855            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7856
 7857        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7858        let tasks = Arc::new(tasks.to_owned());
 7859        Some((buffer, *row, tasks))
 7860    }
 7861
 7862    fn find_enclosing_node_task(
 7863        &mut self,
 7864        cx: &mut Context<Self>,
 7865    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7866        let snapshot = self.buffer.read(cx).snapshot(cx);
 7867        let offset = self.selections.newest::<usize>(cx).head();
 7868        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7869        let buffer_id = excerpt.buffer().remote_id();
 7870
 7871        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7872        let mut cursor = layer.node().walk();
 7873
 7874        while cursor.goto_first_child_for_byte(offset).is_some() {
 7875            if cursor.node().end_byte() == offset {
 7876                cursor.goto_next_sibling();
 7877            }
 7878        }
 7879
 7880        // Ascend to the smallest ancestor that contains the range and has a task.
 7881        loop {
 7882            let node = cursor.node();
 7883            let node_range = node.byte_range();
 7884            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7885
 7886            // Check if this node contains our offset
 7887            if node_range.start <= offset && node_range.end >= offset {
 7888                // If it contains offset, check for task
 7889                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7890                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7891                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7892                }
 7893            }
 7894
 7895            if !cursor.goto_parent() {
 7896                break;
 7897            }
 7898        }
 7899        None
 7900    }
 7901
 7902    fn render_run_indicator(
 7903        &self,
 7904        _style: &EditorStyle,
 7905        is_active: bool,
 7906        row: DisplayRow,
 7907        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7908        cx: &mut Context<Self>,
 7909    ) -> IconButton {
 7910        let color = Color::Muted;
 7911        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7912
 7913        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7914            .shape(ui::IconButtonShape::Square)
 7915            .icon_size(IconSize::XSmall)
 7916            .icon_color(color)
 7917            .toggle_state(is_active)
 7918            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7919                let quick_launch = e.down.button == MouseButton::Left;
 7920                window.focus(&editor.focus_handle(cx));
 7921                editor.toggle_code_actions(
 7922                    &ToggleCodeActions {
 7923                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7924                        quick_launch,
 7925                    },
 7926                    window,
 7927                    cx,
 7928                );
 7929            }))
 7930            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7931                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7932            }))
 7933    }
 7934
 7935    pub fn context_menu_visible(&self) -> bool {
 7936        !self.edit_prediction_preview_is_active()
 7937            && self
 7938                .context_menu
 7939                .borrow()
 7940                .as_ref()
 7941                .map_or(false, |menu| menu.visible())
 7942    }
 7943
 7944    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7945        self.context_menu
 7946            .borrow()
 7947            .as_ref()
 7948            .map(|menu| menu.origin())
 7949    }
 7950
 7951    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7952        self.context_menu_options = Some(options);
 7953    }
 7954
 7955    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7956    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7957
 7958    fn render_edit_prediction_popover(
 7959        &mut self,
 7960        text_bounds: &Bounds<Pixels>,
 7961        content_origin: gpui::Point<Pixels>,
 7962        right_margin: Pixels,
 7963        editor_snapshot: &EditorSnapshot,
 7964        visible_row_range: Range<DisplayRow>,
 7965        scroll_top: f32,
 7966        scroll_bottom: f32,
 7967        line_layouts: &[LineWithInvisibles],
 7968        line_height: Pixels,
 7969        scroll_pixel_position: gpui::Point<Pixels>,
 7970        newest_selection_head: Option<DisplayPoint>,
 7971        editor_width: Pixels,
 7972        style: &EditorStyle,
 7973        window: &mut Window,
 7974        cx: &mut App,
 7975    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7976        if self.mode().is_minimap() {
 7977            return None;
 7978        }
 7979        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7980
 7981        if self.edit_prediction_visible_in_cursor_popover(true) {
 7982            return None;
 7983        }
 7984
 7985        match &active_inline_completion.completion {
 7986            InlineCompletion::Move { target, .. } => {
 7987                let target_display_point = target.to_display_point(editor_snapshot);
 7988
 7989                if self.edit_prediction_requires_modifier() {
 7990                    if !self.edit_prediction_preview_is_active() {
 7991                        return None;
 7992                    }
 7993
 7994                    self.render_edit_prediction_modifier_jump_popover(
 7995                        text_bounds,
 7996                        content_origin,
 7997                        visible_row_range,
 7998                        line_layouts,
 7999                        line_height,
 8000                        scroll_pixel_position,
 8001                        newest_selection_head,
 8002                        target_display_point,
 8003                        window,
 8004                        cx,
 8005                    )
 8006                } else {
 8007                    self.render_edit_prediction_eager_jump_popover(
 8008                        text_bounds,
 8009                        content_origin,
 8010                        editor_snapshot,
 8011                        visible_row_range,
 8012                        scroll_top,
 8013                        scroll_bottom,
 8014                        line_height,
 8015                        scroll_pixel_position,
 8016                        target_display_point,
 8017                        editor_width,
 8018                        window,
 8019                        cx,
 8020                    )
 8021                }
 8022            }
 8023            InlineCompletion::Edit {
 8024                display_mode: EditDisplayMode::Inline,
 8025                ..
 8026            } => None,
 8027            InlineCompletion::Edit {
 8028                display_mode: EditDisplayMode::TabAccept,
 8029                edits,
 8030                ..
 8031            } => {
 8032                let range = &edits.first()?.0;
 8033                let target_display_point = range.end.to_display_point(editor_snapshot);
 8034
 8035                self.render_edit_prediction_end_of_line_popover(
 8036                    "Accept",
 8037                    editor_snapshot,
 8038                    visible_row_range,
 8039                    target_display_point,
 8040                    line_height,
 8041                    scroll_pixel_position,
 8042                    content_origin,
 8043                    editor_width,
 8044                    window,
 8045                    cx,
 8046                )
 8047            }
 8048            InlineCompletion::Edit {
 8049                edits,
 8050                edit_preview,
 8051                display_mode: EditDisplayMode::DiffPopover,
 8052                snapshot,
 8053            } => self.render_edit_prediction_diff_popover(
 8054                text_bounds,
 8055                content_origin,
 8056                right_margin,
 8057                editor_snapshot,
 8058                visible_row_range,
 8059                line_layouts,
 8060                line_height,
 8061                scroll_pixel_position,
 8062                newest_selection_head,
 8063                editor_width,
 8064                style,
 8065                edits,
 8066                edit_preview,
 8067                snapshot,
 8068                window,
 8069                cx,
 8070            ),
 8071        }
 8072    }
 8073
 8074    fn render_edit_prediction_modifier_jump_popover(
 8075        &mut self,
 8076        text_bounds: &Bounds<Pixels>,
 8077        content_origin: gpui::Point<Pixels>,
 8078        visible_row_range: Range<DisplayRow>,
 8079        line_layouts: &[LineWithInvisibles],
 8080        line_height: Pixels,
 8081        scroll_pixel_position: gpui::Point<Pixels>,
 8082        newest_selection_head: Option<DisplayPoint>,
 8083        target_display_point: DisplayPoint,
 8084        window: &mut Window,
 8085        cx: &mut App,
 8086    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8087        let scrolled_content_origin =
 8088            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8089
 8090        const SCROLL_PADDING_Y: Pixels = px(12.);
 8091
 8092        if target_display_point.row() < visible_row_range.start {
 8093            return self.render_edit_prediction_scroll_popover(
 8094                |_| SCROLL_PADDING_Y,
 8095                IconName::ArrowUp,
 8096                visible_row_range,
 8097                line_layouts,
 8098                newest_selection_head,
 8099                scrolled_content_origin,
 8100                window,
 8101                cx,
 8102            );
 8103        } else if target_display_point.row() >= visible_row_range.end {
 8104            return self.render_edit_prediction_scroll_popover(
 8105                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8106                IconName::ArrowDown,
 8107                visible_row_range,
 8108                line_layouts,
 8109                newest_selection_head,
 8110                scrolled_content_origin,
 8111                window,
 8112                cx,
 8113            );
 8114        }
 8115
 8116        const POLE_WIDTH: Pixels = px(2.);
 8117
 8118        let line_layout =
 8119            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8120        let target_column = target_display_point.column() as usize;
 8121
 8122        let target_x = line_layout.x_for_index(target_column);
 8123        let target_y =
 8124            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8125
 8126        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8127
 8128        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8129        border_color.l += 0.001;
 8130
 8131        let mut element = v_flex()
 8132            .items_end()
 8133            .when(flag_on_right, |el| el.items_start())
 8134            .child(if flag_on_right {
 8135                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8136                    .rounded_bl(px(0.))
 8137                    .rounded_tl(px(0.))
 8138                    .border_l_2()
 8139                    .border_color(border_color)
 8140            } else {
 8141                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8142                    .rounded_br(px(0.))
 8143                    .rounded_tr(px(0.))
 8144                    .border_r_2()
 8145                    .border_color(border_color)
 8146            })
 8147            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8148            .into_any();
 8149
 8150        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8151
 8152        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8153            - point(
 8154                if flag_on_right {
 8155                    POLE_WIDTH
 8156                } else {
 8157                    size.width - POLE_WIDTH
 8158                },
 8159                size.height - line_height,
 8160            );
 8161
 8162        origin.x = origin.x.max(content_origin.x);
 8163
 8164        element.prepaint_at(origin, window, cx);
 8165
 8166        Some((element, origin))
 8167    }
 8168
 8169    fn render_edit_prediction_scroll_popover(
 8170        &mut self,
 8171        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8172        scroll_icon: IconName,
 8173        visible_row_range: Range<DisplayRow>,
 8174        line_layouts: &[LineWithInvisibles],
 8175        newest_selection_head: Option<DisplayPoint>,
 8176        scrolled_content_origin: gpui::Point<Pixels>,
 8177        window: &mut Window,
 8178        cx: &mut App,
 8179    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8180        let mut element = self
 8181            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8182            .into_any();
 8183
 8184        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8185
 8186        let cursor = newest_selection_head?;
 8187        let cursor_row_layout =
 8188            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8189        let cursor_column = cursor.column() as usize;
 8190
 8191        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8192
 8193        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8194
 8195        element.prepaint_at(origin, window, cx);
 8196        Some((element, origin))
 8197    }
 8198
 8199    fn render_edit_prediction_eager_jump_popover(
 8200        &mut self,
 8201        text_bounds: &Bounds<Pixels>,
 8202        content_origin: gpui::Point<Pixels>,
 8203        editor_snapshot: &EditorSnapshot,
 8204        visible_row_range: Range<DisplayRow>,
 8205        scroll_top: f32,
 8206        scroll_bottom: f32,
 8207        line_height: Pixels,
 8208        scroll_pixel_position: gpui::Point<Pixels>,
 8209        target_display_point: DisplayPoint,
 8210        editor_width: Pixels,
 8211        window: &mut Window,
 8212        cx: &mut App,
 8213    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8214        if target_display_point.row().as_f32() < scroll_top {
 8215            let mut element = self
 8216                .render_edit_prediction_line_popover(
 8217                    "Jump to Edit",
 8218                    Some(IconName::ArrowUp),
 8219                    window,
 8220                    cx,
 8221                )?
 8222                .into_any();
 8223
 8224            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8225            let offset = point(
 8226                (text_bounds.size.width - size.width) / 2.,
 8227                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8228            );
 8229
 8230            let origin = text_bounds.origin + offset;
 8231            element.prepaint_at(origin, window, cx);
 8232            Some((element, origin))
 8233        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8234            let mut element = self
 8235                .render_edit_prediction_line_popover(
 8236                    "Jump to Edit",
 8237                    Some(IconName::ArrowDown),
 8238                    window,
 8239                    cx,
 8240                )?
 8241                .into_any();
 8242
 8243            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8244            let offset = point(
 8245                (text_bounds.size.width - size.width) / 2.,
 8246                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8247            );
 8248
 8249            let origin = text_bounds.origin + offset;
 8250            element.prepaint_at(origin, window, cx);
 8251            Some((element, origin))
 8252        } else {
 8253            self.render_edit_prediction_end_of_line_popover(
 8254                "Jump to Edit",
 8255                editor_snapshot,
 8256                visible_row_range,
 8257                target_display_point,
 8258                line_height,
 8259                scroll_pixel_position,
 8260                content_origin,
 8261                editor_width,
 8262                window,
 8263                cx,
 8264            )
 8265        }
 8266    }
 8267
 8268    fn render_edit_prediction_end_of_line_popover(
 8269        self: &mut Editor,
 8270        label: &'static str,
 8271        editor_snapshot: &EditorSnapshot,
 8272        visible_row_range: Range<DisplayRow>,
 8273        target_display_point: DisplayPoint,
 8274        line_height: Pixels,
 8275        scroll_pixel_position: gpui::Point<Pixels>,
 8276        content_origin: gpui::Point<Pixels>,
 8277        editor_width: Pixels,
 8278        window: &mut Window,
 8279        cx: &mut App,
 8280    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8281        let target_line_end = DisplayPoint::new(
 8282            target_display_point.row(),
 8283            editor_snapshot.line_len(target_display_point.row()),
 8284        );
 8285
 8286        let mut element = self
 8287            .render_edit_prediction_line_popover(label, None, window, cx)?
 8288            .into_any();
 8289
 8290        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8291
 8292        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8293
 8294        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8295        let mut origin = start_point
 8296            + line_origin
 8297            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8298        origin.x = origin.x.max(content_origin.x);
 8299
 8300        let max_x = content_origin.x + editor_width - size.width;
 8301
 8302        if origin.x > max_x {
 8303            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8304
 8305            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8306                origin.y += offset;
 8307                IconName::ArrowUp
 8308            } else {
 8309                origin.y -= offset;
 8310                IconName::ArrowDown
 8311            };
 8312
 8313            element = self
 8314                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8315                .into_any();
 8316
 8317            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8318
 8319            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8320        }
 8321
 8322        element.prepaint_at(origin, window, cx);
 8323        Some((element, origin))
 8324    }
 8325
 8326    fn render_edit_prediction_diff_popover(
 8327        self: &Editor,
 8328        text_bounds: &Bounds<Pixels>,
 8329        content_origin: gpui::Point<Pixels>,
 8330        right_margin: Pixels,
 8331        editor_snapshot: &EditorSnapshot,
 8332        visible_row_range: Range<DisplayRow>,
 8333        line_layouts: &[LineWithInvisibles],
 8334        line_height: Pixels,
 8335        scroll_pixel_position: gpui::Point<Pixels>,
 8336        newest_selection_head: Option<DisplayPoint>,
 8337        editor_width: Pixels,
 8338        style: &EditorStyle,
 8339        edits: &Vec<(Range<Anchor>, String)>,
 8340        edit_preview: &Option<language::EditPreview>,
 8341        snapshot: &language::BufferSnapshot,
 8342        window: &mut Window,
 8343        cx: &mut App,
 8344    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8345        let edit_start = edits
 8346            .first()
 8347            .unwrap()
 8348            .0
 8349            .start
 8350            .to_display_point(editor_snapshot);
 8351        let edit_end = edits
 8352            .last()
 8353            .unwrap()
 8354            .0
 8355            .end
 8356            .to_display_point(editor_snapshot);
 8357
 8358        let is_visible = visible_row_range.contains(&edit_start.row())
 8359            || visible_row_range.contains(&edit_end.row());
 8360        if !is_visible {
 8361            return None;
 8362        }
 8363
 8364        let highlighted_edits =
 8365            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8366
 8367        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8368        let line_count = highlighted_edits.text.lines().count();
 8369
 8370        const BORDER_WIDTH: Pixels = px(1.);
 8371
 8372        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8373        let has_keybind = keybind.is_some();
 8374
 8375        let mut element = h_flex()
 8376            .items_start()
 8377            .child(
 8378                h_flex()
 8379                    .bg(cx.theme().colors().editor_background)
 8380                    .border(BORDER_WIDTH)
 8381                    .shadow_sm()
 8382                    .border_color(cx.theme().colors().border)
 8383                    .rounded_l_lg()
 8384                    .when(line_count > 1, |el| el.rounded_br_lg())
 8385                    .pr_1()
 8386                    .child(styled_text),
 8387            )
 8388            .child(
 8389                h_flex()
 8390                    .h(line_height + BORDER_WIDTH * 2.)
 8391                    .px_1p5()
 8392                    .gap_1()
 8393                    // Workaround: For some reason, there's a gap if we don't do this
 8394                    .ml(-BORDER_WIDTH)
 8395                    .shadow(vec![gpui::BoxShadow {
 8396                        color: gpui::black().opacity(0.05),
 8397                        offset: point(px(1.), px(1.)),
 8398                        blur_radius: px(2.),
 8399                        spread_radius: px(0.),
 8400                    }])
 8401                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8402                    .border(BORDER_WIDTH)
 8403                    .border_color(cx.theme().colors().border)
 8404                    .rounded_r_lg()
 8405                    .id("edit_prediction_diff_popover_keybind")
 8406                    .when(!has_keybind, |el| {
 8407                        let status_colors = cx.theme().status();
 8408
 8409                        el.bg(status_colors.error_background)
 8410                            .border_color(status_colors.error.opacity(0.6))
 8411                            .child(Icon::new(IconName::Info).color(Color::Error))
 8412                            .cursor_default()
 8413                            .hoverable_tooltip(move |_window, cx| {
 8414                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8415                            })
 8416                    })
 8417                    .children(keybind),
 8418            )
 8419            .into_any();
 8420
 8421        let longest_row =
 8422            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8423        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8424            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8425        } else {
 8426            layout_line(
 8427                longest_row,
 8428                editor_snapshot,
 8429                style,
 8430                editor_width,
 8431                |_| false,
 8432                window,
 8433                cx,
 8434            )
 8435            .width
 8436        };
 8437
 8438        let viewport_bounds =
 8439            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8440                right: -right_margin,
 8441                ..Default::default()
 8442            });
 8443
 8444        let x_after_longest =
 8445            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8446                - scroll_pixel_position.x;
 8447
 8448        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8449
 8450        // Fully visible if it can be displayed within the window (allow overlapping other
 8451        // panes). However, this is only allowed if the popover starts within text_bounds.
 8452        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8453            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8454
 8455        let mut origin = if can_position_to_the_right {
 8456            point(
 8457                x_after_longest,
 8458                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8459                    - scroll_pixel_position.y,
 8460            )
 8461        } else {
 8462            let cursor_row = newest_selection_head.map(|head| head.row());
 8463            let above_edit = edit_start
 8464                .row()
 8465                .0
 8466                .checked_sub(line_count as u32)
 8467                .map(DisplayRow);
 8468            let below_edit = Some(edit_end.row() + 1);
 8469            let above_cursor =
 8470                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8471            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8472
 8473            // Place the edit popover adjacent to the edit if there is a location
 8474            // available that is onscreen and does not obscure the cursor. Otherwise,
 8475            // place it adjacent to the cursor.
 8476            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8477                .into_iter()
 8478                .flatten()
 8479                .find(|&start_row| {
 8480                    let end_row = start_row + line_count as u32;
 8481                    visible_row_range.contains(&start_row)
 8482                        && visible_row_range.contains(&end_row)
 8483                        && cursor_row.map_or(true, |cursor_row| {
 8484                            !((start_row..end_row).contains(&cursor_row))
 8485                        })
 8486                })?;
 8487
 8488            content_origin
 8489                + point(
 8490                    -scroll_pixel_position.x,
 8491                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8492                )
 8493        };
 8494
 8495        origin.x -= BORDER_WIDTH;
 8496
 8497        window.defer_draw(element, origin, 1);
 8498
 8499        // Do not return an element, since it will already be drawn due to defer_draw.
 8500        None
 8501    }
 8502
 8503    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8504        px(30.)
 8505    }
 8506
 8507    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8508        if self.read_only(cx) {
 8509            cx.theme().players().read_only()
 8510        } else {
 8511            self.style.as_ref().unwrap().local_player
 8512        }
 8513    }
 8514
 8515    fn render_edit_prediction_accept_keybind(
 8516        &self,
 8517        window: &mut Window,
 8518        cx: &App,
 8519    ) -> Option<AnyElement> {
 8520        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8521        let accept_keystroke = accept_binding.keystroke()?;
 8522
 8523        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8524
 8525        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8526            Color::Accent
 8527        } else {
 8528            Color::Muted
 8529        };
 8530
 8531        h_flex()
 8532            .px_0p5()
 8533            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8534            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8535            .text_size(TextSize::XSmall.rems(cx))
 8536            .child(h_flex().children(ui::render_modifiers(
 8537                &accept_keystroke.modifiers,
 8538                PlatformStyle::platform(),
 8539                Some(modifiers_color),
 8540                Some(IconSize::XSmall.rems().into()),
 8541                true,
 8542            )))
 8543            .when(is_platform_style_mac, |parent| {
 8544                parent.child(accept_keystroke.key.clone())
 8545            })
 8546            .when(!is_platform_style_mac, |parent| {
 8547                parent.child(
 8548                    Key::new(
 8549                        util::capitalize(&accept_keystroke.key),
 8550                        Some(Color::Default),
 8551                    )
 8552                    .size(Some(IconSize::XSmall.rems().into())),
 8553                )
 8554            })
 8555            .into_any()
 8556            .into()
 8557    }
 8558
 8559    fn render_edit_prediction_line_popover(
 8560        &self,
 8561        label: impl Into<SharedString>,
 8562        icon: Option<IconName>,
 8563        window: &mut Window,
 8564        cx: &App,
 8565    ) -> Option<Stateful<Div>> {
 8566        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8567
 8568        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8569        let has_keybind = keybind.is_some();
 8570
 8571        let result = h_flex()
 8572            .id("ep-line-popover")
 8573            .py_0p5()
 8574            .pl_1()
 8575            .pr(padding_right)
 8576            .gap_1()
 8577            .rounded_md()
 8578            .border_1()
 8579            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8580            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8581            .shadow_sm()
 8582            .when(!has_keybind, |el| {
 8583                let status_colors = cx.theme().status();
 8584
 8585                el.bg(status_colors.error_background)
 8586                    .border_color(status_colors.error.opacity(0.6))
 8587                    .pl_2()
 8588                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8589                    .cursor_default()
 8590                    .hoverable_tooltip(move |_window, cx| {
 8591                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8592                    })
 8593            })
 8594            .children(keybind)
 8595            .child(
 8596                Label::new(label)
 8597                    .size(LabelSize::Small)
 8598                    .when(!has_keybind, |el| {
 8599                        el.color(cx.theme().status().error.into()).strikethrough()
 8600                    }),
 8601            )
 8602            .when(!has_keybind, |el| {
 8603                el.child(
 8604                    h_flex().ml_1().child(
 8605                        Icon::new(IconName::Info)
 8606                            .size(IconSize::Small)
 8607                            .color(cx.theme().status().error.into()),
 8608                    ),
 8609                )
 8610            })
 8611            .when_some(icon, |element, icon| {
 8612                element.child(
 8613                    div()
 8614                        .mt(px(1.5))
 8615                        .child(Icon::new(icon).size(IconSize::Small)),
 8616                )
 8617            });
 8618
 8619        Some(result)
 8620    }
 8621
 8622    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8623        let accent_color = cx.theme().colors().text_accent;
 8624        let editor_bg_color = cx.theme().colors().editor_background;
 8625        editor_bg_color.blend(accent_color.opacity(0.1))
 8626    }
 8627
 8628    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8629        let accent_color = cx.theme().colors().text_accent;
 8630        let editor_bg_color = cx.theme().colors().editor_background;
 8631        editor_bg_color.blend(accent_color.opacity(0.6))
 8632    }
 8633
 8634    fn render_edit_prediction_cursor_popover(
 8635        &self,
 8636        min_width: Pixels,
 8637        max_width: Pixels,
 8638        cursor_point: Point,
 8639        style: &EditorStyle,
 8640        accept_keystroke: Option<&gpui::Keystroke>,
 8641        _window: &Window,
 8642        cx: &mut Context<Editor>,
 8643    ) -> Option<AnyElement> {
 8644        let provider = self.edit_prediction_provider.as_ref()?;
 8645
 8646        if provider.provider.needs_terms_acceptance(cx) {
 8647            return Some(
 8648                h_flex()
 8649                    .min_w(min_width)
 8650                    .flex_1()
 8651                    .px_2()
 8652                    .py_1()
 8653                    .gap_3()
 8654                    .elevation_2(cx)
 8655                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8656                    .id("accept-terms")
 8657                    .cursor_pointer()
 8658                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8659                    .on_click(cx.listener(|this, _event, window, cx| {
 8660                        cx.stop_propagation();
 8661                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8662                        window.dispatch_action(
 8663                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8664                            cx,
 8665                        );
 8666                    }))
 8667                    .child(
 8668                        h_flex()
 8669                            .flex_1()
 8670                            .gap_2()
 8671                            .child(Icon::new(IconName::ZedPredict))
 8672                            .child(Label::new("Accept Terms of Service"))
 8673                            .child(div().w_full())
 8674                            .child(
 8675                                Icon::new(IconName::ArrowUpRight)
 8676                                    .color(Color::Muted)
 8677                                    .size(IconSize::Small),
 8678                            )
 8679                            .into_any_element(),
 8680                    )
 8681                    .into_any(),
 8682            );
 8683        }
 8684
 8685        let is_refreshing = provider.provider.is_refreshing(cx);
 8686
 8687        fn pending_completion_container() -> Div {
 8688            h_flex()
 8689                .h_full()
 8690                .flex_1()
 8691                .gap_2()
 8692                .child(Icon::new(IconName::ZedPredict))
 8693        }
 8694
 8695        let completion = match &self.active_inline_completion {
 8696            Some(prediction) => {
 8697                if !self.has_visible_completions_menu() {
 8698                    const RADIUS: Pixels = px(6.);
 8699                    const BORDER_WIDTH: Pixels = px(1.);
 8700
 8701                    return Some(
 8702                        h_flex()
 8703                            .elevation_2(cx)
 8704                            .border(BORDER_WIDTH)
 8705                            .border_color(cx.theme().colors().border)
 8706                            .when(accept_keystroke.is_none(), |el| {
 8707                                el.border_color(cx.theme().status().error)
 8708                            })
 8709                            .rounded(RADIUS)
 8710                            .rounded_tl(px(0.))
 8711                            .overflow_hidden()
 8712                            .child(div().px_1p5().child(match &prediction.completion {
 8713                                InlineCompletion::Move { target, snapshot } => {
 8714                                    use text::ToPoint as _;
 8715                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8716                                    {
 8717                                        Icon::new(IconName::ZedPredictDown)
 8718                                    } else {
 8719                                        Icon::new(IconName::ZedPredictUp)
 8720                                    }
 8721                                }
 8722                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8723                            }))
 8724                            .child(
 8725                                h_flex()
 8726                                    .gap_1()
 8727                                    .py_1()
 8728                                    .px_2()
 8729                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8730                                    .border_l_1()
 8731                                    .border_color(cx.theme().colors().border)
 8732                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8733                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8734                                        el.child(
 8735                                            Label::new("Hold")
 8736                                                .size(LabelSize::Small)
 8737                                                .when(accept_keystroke.is_none(), |el| {
 8738                                                    el.strikethrough()
 8739                                                })
 8740                                                .line_height_style(LineHeightStyle::UiLabel),
 8741                                        )
 8742                                    })
 8743                                    .id("edit_prediction_cursor_popover_keybind")
 8744                                    .when(accept_keystroke.is_none(), |el| {
 8745                                        let status_colors = cx.theme().status();
 8746
 8747                                        el.bg(status_colors.error_background)
 8748                                            .border_color(status_colors.error.opacity(0.6))
 8749                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8750                                            .cursor_default()
 8751                                            .hoverable_tooltip(move |_window, cx| {
 8752                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8753                                                    .into()
 8754                                            })
 8755                                    })
 8756                                    .when_some(
 8757                                        accept_keystroke.as_ref(),
 8758                                        |el, accept_keystroke| {
 8759                                            el.child(h_flex().children(ui::render_modifiers(
 8760                                                &accept_keystroke.modifiers,
 8761                                                PlatformStyle::platform(),
 8762                                                Some(Color::Default),
 8763                                                Some(IconSize::XSmall.rems().into()),
 8764                                                false,
 8765                                            )))
 8766                                        },
 8767                                    ),
 8768                            )
 8769                            .into_any(),
 8770                    );
 8771                }
 8772
 8773                self.render_edit_prediction_cursor_popover_preview(
 8774                    prediction,
 8775                    cursor_point,
 8776                    style,
 8777                    cx,
 8778                )?
 8779            }
 8780
 8781            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8782                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8783                    stale_completion,
 8784                    cursor_point,
 8785                    style,
 8786                    cx,
 8787                )?,
 8788
 8789                None => {
 8790                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8791                }
 8792            },
 8793
 8794            None => pending_completion_container().child(Label::new("No Prediction")),
 8795        };
 8796
 8797        let completion = if is_refreshing {
 8798            completion
 8799                .with_animation(
 8800                    "loading-completion",
 8801                    Animation::new(Duration::from_secs(2))
 8802                        .repeat()
 8803                        .with_easing(pulsating_between(0.4, 0.8)),
 8804                    |label, delta| label.opacity(delta),
 8805                )
 8806                .into_any_element()
 8807        } else {
 8808            completion.into_any_element()
 8809        };
 8810
 8811        let has_completion = self.active_inline_completion.is_some();
 8812
 8813        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8814        Some(
 8815            h_flex()
 8816                .min_w(min_width)
 8817                .max_w(max_width)
 8818                .flex_1()
 8819                .elevation_2(cx)
 8820                .border_color(cx.theme().colors().border)
 8821                .child(
 8822                    div()
 8823                        .flex_1()
 8824                        .py_1()
 8825                        .px_2()
 8826                        .overflow_hidden()
 8827                        .child(completion),
 8828                )
 8829                .when_some(accept_keystroke, |el, accept_keystroke| {
 8830                    if !accept_keystroke.modifiers.modified() {
 8831                        return el;
 8832                    }
 8833
 8834                    el.child(
 8835                        h_flex()
 8836                            .h_full()
 8837                            .border_l_1()
 8838                            .rounded_r_lg()
 8839                            .border_color(cx.theme().colors().border)
 8840                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8841                            .gap_1()
 8842                            .py_1()
 8843                            .px_2()
 8844                            .child(
 8845                                h_flex()
 8846                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8847                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8848                                    .child(h_flex().children(ui::render_modifiers(
 8849                                        &accept_keystroke.modifiers,
 8850                                        PlatformStyle::platform(),
 8851                                        Some(if !has_completion {
 8852                                            Color::Muted
 8853                                        } else {
 8854                                            Color::Default
 8855                                        }),
 8856                                        None,
 8857                                        false,
 8858                                    ))),
 8859                            )
 8860                            .child(Label::new("Preview").into_any_element())
 8861                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8862                    )
 8863                })
 8864                .into_any(),
 8865        )
 8866    }
 8867
 8868    fn render_edit_prediction_cursor_popover_preview(
 8869        &self,
 8870        completion: &InlineCompletionState,
 8871        cursor_point: Point,
 8872        style: &EditorStyle,
 8873        cx: &mut Context<Editor>,
 8874    ) -> Option<Div> {
 8875        use text::ToPoint as _;
 8876
 8877        fn render_relative_row_jump(
 8878            prefix: impl Into<String>,
 8879            current_row: u32,
 8880            target_row: u32,
 8881        ) -> Div {
 8882            let (row_diff, arrow) = if target_row < current_row {
 8883                (current_row - target_row, IconName::ArrowUp)
 8884            } else {
 8885                (target_row - current_row, IconName::ArrowDown)
 8886            };
 8887
 8888            h_flex()
 8889                .child(
 8890                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8891                        .color(Color::Muted)
 8892                        .size(LabelSize::Small),
 8893                )
 8894                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8895        }
 8896
 8897        match &completion.completion {
 8898            InlineCompletion::Move {
 8899                target, snapshot, ..
 8900            } => Some(
 8901                h_flex()
 8902                    .px_2()
 8903                    .gap_2()
 8904                    .flex_1()
 8905                    .child(
 8906                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8907                            Icon::new(IconName::ZedPredictDown)
 8908                        } else {
 8909                            Icon::new(IconName::ZedPredictUp)
 8910                        },
 8911                    )
 8912                    .child(Label::new("Jump to Edit")),
 8913            ),
 8914
 8915            InlineCompletion::Edit {
 8916                edits,
 8917                edit_preview,
 8918                snapshot,
 8919                display_mode: _,
 8920            } => {
 8921                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8922
 8923                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8924                    &snapshot,
 8925                    &edits,
 8926                    edit_preview.as_ref()?,
 8927                    true,
 8928                    cx,
 8929                )
 8930                .first_line_preview();
 8931
 8932                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8933                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8934
 8935                let preview = h_flex()
 8936                    .gap_1()
 8937                    .min_w_16()
 8938                    .child(styled_text)
 8939                    .when(has_more_lines, |parent| parent.child(""));
 8940
 8941                let left = if first_edit_row != cursor_point.row {
 8942                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8943                        .into_any_element()
 8944                } else {
 8945                    Icon::new(IconName::ZedPredict).into_any_element()
 8946                };
 8947
 8948                Some(
 8949                    h_flex()
 8950                        .h_full()
 8951                        .flex_1()
 8952                        .gap_2()
 8953                        .pr_1()
 8954                        .overflow_x_hidden()
 8955                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8956                        .child(left)
 8957                        .child(preview),
 8958                )
 8959            }
 8960        }
 8961    }
 8962
 8963    pub fn render_context_menu(
 8964        &self,
 8965        style: &EditorStyle,
 8966        max_height_in_lines: u32,
 8967        window: &mut Window,
 8968        cx: &mut Context<Editor>,
 8969    ) -> Option<AnyElement> {
 8970        let menu = self.context_menu.borrow();
 8971        let menu = menu.as_ref()?;
 8972        if !menu.visible() {
 8973            return None;
 8974        };
 8975        Some(menu.render(style, max_height_in_lines, window, cx))
 8976    }
 8977
 8978    fn render_context_menu_aside(
 8979        &mut self,
 8980        max_size: Size<Pixels>,
 8981        window: &mut Window,
 8982        cx: &mut Context<Editor>,
 8983    ) -> Option<AnyElement> {
 8984        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8985            if menu.visible() {
 8986                menu.render_aside(max_size, window, cx)
 8987            } else {
 8988                None
 8989            }
 8990        })
 8991    }
 8992
 8993    fn hide_context_menu(
 8994        &mut self,
 8995        window: &mut Window,
 8996        cx: &mut Context<Self>,
 8997    ) -> Option<CodeContextMenu> {
 8998        cx.notify();
 8999        self.completion_tasks.clear();
 9000        let context_menu = self.context_menu.borrow_mut().take();
 9001        self.stale_inline_completion_in_menu.take();
 9002        self.update_visible_inline_completion(window, cx);
 9003        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9004            if let Some(completion_provider) = &self.completion_provider {
 9005                completion_provider.selection_changed(None, window, cx);
 9006            }
 9007        }
 9008        context_menu
 9009    }
 9010
 9011    fn show_snippet_choices(
 9012        &mut self,
 9013        choices: &Vec<String>,
 9014        selection: Range<Anchor>,
 9015        cx: &mut Context<Self>,
 9016    ) {
 9017        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9018            (Some(a), Some(b)) if a == b => a,
 9019            _ => {
 9020                log::error!("expected anchor range to have matching buffer IDs");
 9021                return;
 9022            }
 9023        };
 9024        let multi_buffer = self.buffer().read(cx);
 9025        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9026            return;
 9027        };
 9028
 9029        let id = post_inc(&mut self.next_completion_id);
 9030        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9031        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9032            CompletionsMenu::new_snippet_choices(
 9033                id,
 9034                true,
 9035                choices,
 9036                selection,
 9037                buffer,
 9038                snippet_sort_order,
 9039            ),
 9040        ));
 9041    }
 9042
 9043    pub fn insert_snippet(
 9044        &mut self,
 9045        insertion_ranges: &[Range<usize>],
 9046        snippet: Snippet,
 9047        window: &mut Window,
 9048        cx: &mut Context<Self>,
 9049    ) -> Result<()> {
 9050        struct Tabstop<T> {
 9051            is_end_tabstop: bool,
 9052            ranges: Vec<Range<T>>,
 9053            choices: Option<Vec<String>>,
 9054        }
 9055
 9056        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9057            let snippet_text: Arc<str> = snippet.text.clone().into();
 9058            let edits = insertion_ranges
 9059                .iter()
 9060                .cloned()
 9061                .map(|range| (range, snippet_text.clone()));
 9062            let autoindent_mode = AutoindentMode::Block {
 9063                original_indent_columns: Vec::new(),
 9064            };
 9065            buffer.edit(edits, Some(autoindent_mode), cx);
 9066
 9067            let snapshot = &*buffer.read(cx);
 9068            let snippet = &snippet;
 9069            snippet
 9070                .tabstops
 9071                .iter()
 9072                .map(|tabstop| {
 9073                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9074                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9075                    });
 9076                    let mut tabstop_ranges = tabstop
 9077                        .ranges
 9078                        .iter()
 9079                        .flat_map(|tabstop_range| {
 9080                            let mut delta = 0_isize;
 9081                            insertion_ranges.iter().map(move |insertion_range| {
 9082                                let insertion_start = insertion_range.start as isize + delta;
 9083                                delta +=
 9084                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9085
 9086                                let start = ((insertion_start + tabstop_range.start) as usize)
 9087                                    .min(snapshot.len());
 9088                                let end = ((insertion_start + tabstop_range.end) as usize)
 9089                                    .min(snapshot.len());
 9090                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9091                            })
 9092                        })
 9093                        .collect::<Vec<_>>();
 9094                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9095
 9096                    Tabstop {
 9097                        is_end_tabstop,
 9098                        ranges: tabstop_ranges,
 9099                        choices: tabstop.choices.clone(),
 9100                    }
 9101                })
 9102                .collect::<Vec<_>>()
 9103        });
 9104        if let Some(tabstop) = tabstops.first() {
 9105            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9106                // Reverse order so that the first range is the newest created selection.
 9107                // Completions will use it and autoscroll will prioritize it.
 9108                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9109            });
 9110
 9111            if let Some(choices) = &tabstop.choices {
 9112                if let Some(selection) = tabstop.ranges.first() {
 9113                    self.show_snippet_choices(choices, selection.clone(), cx)
 9114                }
 9115            }
 9116
 9117            // If we're already at the last tabstop and it's at the end of the snippet,
 9118            // we're done, we don't need to keep the state around.
 9119            if !tabstop.is_end_tabstop {
 9120                let choices = tabstops
 9121                    .iter()
 9122                    .map(|tabstop| tabstop.choices.clone())
 9123                    .collect();
 9124
 9125                let ranges = tabstops
 9126                    .into_iter()
 9127                    .map(|tabstop| tabstop.ranges)
 9128                    .collect::<Vec<_>>();
 9129
 9130                self.snippet_stack.push(SnippetState {
 9131                    active_index: 0,
 9132                    ranges,
 9133                    choices,
 9134                });
 9135            }
 9136
 9137            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9138            if self.autoclose_regions.is_empty() {
 9139                let snapshot = self.buffer.read(cx).snapshot(cx);
 9140                for selection in &mut self.selections.all::<Point>(cx) {
 9141                    let selection_head = selection.head();
 9142                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9143                        continue;
 9144                    };
 9145
 9146                    let mut bracket_pair = None;
 9147                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9148                    let prev_chars = snapshot
 9149                        .reversed_chars_at(selection_head)
 9150                        .collect::<String>();
 9151                    for (pair, enabled) in scope.brackets() {
 9152                        if enabled
 9153                            && pair.close
 9154                            && prev_chars.starts_with(pair.start.as_str())
 9155                            && next_chars.starts_with(pair.end.as_str())
 9156                        {
 9157                            bracket_pair = Some(pair.clone());
 9158                            break;
 9159                        }
 9160                    }
 9161                    if let Some(pair) = bracket_pair {
 9162                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9163                        let autoclose_enabled =
 9164                            self.use_autoclose && snapshot_settings.use_autoclose;
 9165                        if autoclose_enabled {
 9166                            let start = snapshot.anchor_after(selection_head);
 9167                            let end = snapshot.anchor_after(selection_head);
 9168                            self.autoclose_regions.push(AutocloseRegion {
 9169                                selection_id: selection.id,
 9170                                range: start..end,
 9171                                pair,
 9172                            });
 9173                        }
 9174                    }
 9175                }
 9176            }
 9177        }
 9178        Ok(())
 9179    }
 9180
 9181    pub fn move_to_next_snippet_tabstop(
 9182        &mut self,
 9183        window: &mut Window,
 9184        cx: &mut Context<Self>,
 9185    ) -> bool {
 9186        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9187    }
 9188
 9189    pub fn move_to_prev_snippet_tabstop(
 9190        &mut self,
 9191        window: &mut Window,
 9192        cx: &mut Context<Self>,
 9193    ) -> bool {
 9194        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9195    }
 9196
 9197    pub fn move_to_snippet_tabstop(
 9198        &mut self,
 9199        bias: Bias,
 9200        window: &mut Window,
 9201        cx: &mut Context<Self>,
 9202    ) -> bool {
 9203        if let Some(mut snippet) = self.snippet_stack.pop() {
 9204            match bias {
 9205                Bias::Left => {
 9206                    if snippet.active_index > 0 {
 9207                        snippet.active_index -= 1;
 9208                    } else {
 9209                        self.snippet_stack.push(snippet);
 9210                        return false;
 9211                    }
 9212                }
 9213                Bias::Right => {
 9214                    if snippet.active_index + 1 < snippet.ranges.len() {
 9215                        snippet.active_index += 1;
 9216                    } else {
 9217                        self.snippet_stack.push(snippet);
 9218                        return false;
 9219                    }
 9220                }
 9221            }
 9222            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9223                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9224                    // Reverse order so that the first range is the newest created selection.
 9225                    // Completions will use it and autoscroll will prioritize it.
 9226                    s.select_ranges(current_ranges.iter().rev().cloned())
 9227                });
 9228
 9229                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9230                    if let Some(selection) = current_ranges.first() {
 9231                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9232                    }
 9233                }
 9234
 9235                // If snippet state is not at the last tabstop, push it back on the stack
 9236                if snippet.active_index + 1 < snippet.ranges.len() {
 9237                    self.snippet_stack.push(snippet);
 9238                }
 9239                return true;
 9240            }
 9241        }
 9242
 9243        false
 9244    }
 9245
 9246    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9247        self.transact(window, cx, |this, window, cx| {
 9248            this.select_all(&SelectAll, window, cx);
 9249            this.insert("", window, cx);
 9250        });
 9251    }
 9252
 9253    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9254        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9255        self.transact(window, cx, |this, window, cx| {
 9256            this.select_autoclose_pair(window, cx);
 9257            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9258            if !this.linked_edit_ranges.is_empty() {
 9259                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9260                let snapshot = this.buffer.read(cx).snapshot(cx);
 9261
 9262                for selection in selections.iter() {
 9263                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9264                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9265                    if selection_start.buffer_id != selection_end.buffer_id {
 9266                        continue;
 9267                    }
 9268                    if let Some(ranges) =
 9269                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9270                    {
 9271                        for (buffer, entries) in ranges {
 9272                            linked_ranges.entry(buffer).or_default().extend(entries);
 9273                        }
 9274                    }
 9275                }
 9276            }
 9277
 9278            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9279            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9280            for selection in &mut selections {
 9281                if selection.is_empty() {
 9282                    let old_head = selection.head();
 9283                    let mut new_head =
 9284                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9285                            .to_point(&display_map);
 9286                    if let Some((buffer, line_buffer_range)) = display_map
 9287                        .buffer_snapshot
 9288                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9289                    {
 9290                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9291                        let indent_len = match indent_size.kind {
 9292                            IndentKind::Space => {
 9293                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9294                            }
 9295                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9296                        };
 9297                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9298                            let indent_len = indent_len.get();
 9299                            new_head = cmp::min(
 9300                                new_head,
 9301                                MultiBufferPoint::new(
 9302                                    old_head.row,
 9303                                    ((old_head.column - 1) / indent_len) * indent_len,
 9304                                ),
 9305                            );
 9306                        }
 9307                    }
 9308
 9309                    selection.set_head(new_head, SelectionGoal::None);
 9310                }
 9311            }
 9312
 9313            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9314                s.select(selections)
 9315            });
 9316            this.insert("", window, cx);
 9317            let empty_str: Arc<str> = Arc::from("");
 9318            for (buffer, edits) in linked_ranges {
 9319                let snapshot = buffer.read(cx).snapshot();
 9320                use text::ToPoint as TP;
 9321
 9322                let edits = edits
 9323                    .into_iter()
 9324                    .map(|range| {
 9325                        let end_point = TP::to_point(&range.end, &snapshot);
 9326                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9327
 9328                        if end_point == start_point {
 9329                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9330                                .saturating_sub(1);
 9331                            start_point =
 9332                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9333                        };
 9334
 9335                        (start_point..end_point, empty_str.clone())
 9336                    })
 9337                    .sorted_by_key(|(range, _)| range.start)
 9338                    .collect::<Vec<_>>();
 9339                buffer.update(cx, |this, cx| {
 9340                    this.edit(edits, None, cx);
 9341                })
 9342            }
 9343            this.refresh_inline_completion(true, false, window, cx);
 9344            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9345        });
 9346    }
 9347
 9348    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9349        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9350        self.transact(window, cx, |this, window, cx| {
 9351            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9352                s.move_with(|map, selection| {
 9353                    if selection.is_empty() {
 9354                        let cursor = movement::right(map, selection.head());
 9355                        selection.end = cursor;
 9356                        selection.reversed = true;
 9357                        selection.goal = SelectionGoal::None;
 9358                    }
 9359                })
 9360            });
 9361            this.insert("", window, cx);
 9362            this.refresh_inline_completion(true, false, window, cx);
 9363        });
 9364    }
 9365
 9366    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9367        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9368        if self.move_to_prev_snippet_tabstop(window, cx) {
 9369            return;
 9370        }
 9371        self.outdent(&Outdent, window, cx);
 9372    }
 9373
 9374    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9375        if self.move_to_next_snippet_tabstop(window, cx) {
 9376            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9377            return;
 9378        }
 9379        if self.read_only(cx) {
 9380            return;
 9381        }
 9382        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9383        let mut selections = self.selections.all_adjusted(cx);
 9384        let buffer = self.buffer.read(cx);
 9385        let snapshot = buffer.snapshot(cx);
 9386        let rows_iter = selections.iter().map(|s| s.head().row);
 9387        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9388
 9389        let has_some_cursor_in_whitespace = selections
 9390            .iter()
 9391            .filter(|selection| selection.is_empty())
 9392            .any(|selection| {
 9393                let cursor = selection.head();
 9394                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9395                cursor.column < current_indent.len
 9396            });
 9397
 9398        let mut edits = Vec::new();
 9399        let mut prev_edited_row = 0;
 9400        let mut row_delta = 0;
 9401        for selection in &mut selections {
 9402            if selection.start.row != prev_edited_row {
 9403                row_delta = 0;
 9404            }
 9405            prev_edited_row = selection.end.row;
 9406
 9407            // If the selection is non-empty, then increase the indentation of the selected lines.
 9408            if !selection.is_empty() {
 9409                row_delta =
 9410                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9411                continue;
 9412            }
 9413
 9414            let cursor = selection.head();
 9415            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9416            if let Some(suggested_indent) =
 9417                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9418            {
 9419                // Don't do anything if already at suggested indent
 9420                // and there is any other cursor which is not
 9421                if has_some_cursor_in_whitespace
 9422                    && cursor.column == current_indent.len
 9423                    && current_indent.len == suggested_indent.len
 9424                {
 9425                    continue;
 9426                }
 9427
 9428                // Adjust line and move cursor to suggested indent
 9429                // if cursor is not at suggested indent
 9430                if cursor.column < suggested_indent.len
 9431                    && cursor.column <= current_indent.len
 9432                    && current_indent.len <= suggested_indent.len
 9433                {
 9434                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9435                    selection.end = selection.start;
 9436                    if row_delta == 0 {
 9437                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9438                            cursor.row,
 9439                            current_indent,
 9440                            suggested_indent,
 9441                        ));
 9442                        row_delta = suggested_indent.len - current_indent.len;
 9443                    }
 9444                    continue;
 9445                }
 9446
 9447                // If current indent is more than suggested indent
 9448                // only move cursor to current indent and skip indent
 9449                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9450                    selection.start = Point::new(cursor.row, current_indent.len);
 9451                    selection.end = selection.start;
 9452                    continue;
 9453                }
 9454            }
 9455
 9456            // Otherwise, insert a hard or soft tab.
 9457            let settings = buffer.language_settings_at(cursor, cx);
 9458            let tab_size = if settings.hard_tabs {
 9459                IndentSize::tab()
 9460            } else {
 9461                let tab_size = settings.tab_size.get();
 9462                let indent_remainder = snapshot
 9463                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9464                    .flat_map(str::chars)
 9465                    .fold(row_delta % tab_size, |counter: u32, c| {
 9466                        if c == '\t' {
 9467                            0
 9468                        } else {
 9469                            (counter + 1) % tab_size
 9470                        }
 9471                    });
 9472
 9473                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9474                IndentSize::spaces(chars_to_next_tab_stop)
 9475            };
 9476            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9477            selection.end = selection.start;
 9478            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9479            row_delta += tab_size.len;
 9480        }
 9481
 9482        self.transact(window, cx, |this, window, cx| {
 9483            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9484            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9485                s.select(selections)
 9486            });
 9487            this.refresh_inline_completion(true, false, window, cx);
 9488        });
 9489    }
 9490
 9491    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9492        if self.read_only(cx) {
 9493            return;
 9494        }
 9495        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9496        let mut selections = self.selections.all::<Point>(cx);
 9497        let mut prev_edited_row = 0;
 9498        let mut row_delta = 0;
 9499        let mut edits = Vec::new();
 9500        let buffer = self.buffer.read(cx);
 9501        let snapshot = buffer.snapshot(cx);
 9502        for selection in &mut selections {
 9503            if selection.start.row != prev_edited_row {
 9504                row_delta = 0;
 9505            }
 9506            prev_edited_row = selection.end.row;
 9507
 9508            row_delta =
 9509                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9510        }
 9511
 9512        self.transact(window, cx, |this, window, cx| {
 9513            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9514            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9515                s.select(selections)
 9516            });
 9517        });
 9518    }
 9519
 9520    fn indent_selection(
 9521        buffer: &MultiBuffer,
 9522        snapshot: &MultiBufferSnapshot,
 9523        selection: &mut Selection<Point>,
 9524        edits: &mut Vec<(Range<Point>, String)>,
 9525        delta_for_start_row: u32,
 9526        cx: &App,
 9527    ) -> u32 {
 9528        let settings = buffer.language_settings_at(selection.start, cx);
 9529        let tab_size = settings.tab_size.get();
 9530        let indent_kind = if settings.hard_tabs {
 9531            IndentKind::Tab
 9532        } else {
 9533            IndentKind::Space
 9534        };
 9535        let mut start_row = selection.start.row;
 9536        let mut end_row = selection.end.row + 1;
 9537
 9538        // If a selection ends at the beginning of a line, don't indent
 9539        // that last line.
 9540        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9541            end_row -= 1;
 9542        }
 9543
 9544        // Avoid re-indenting a row that has already been indented by a
 9545        // previous selection, but still update this selection's column
 9546        // to reflect that indentation.
 9547        if delta_for_start_row > 0 {
 9548            start_row += 1;
 9549            selection.start.column += delta_for_start_row;
 9550            if selection.end.row == selection.start.row {
 9551                selection.end.column += delta_for_start_row;
 9552            }
 9553        }
 9554
 9555        let mut delta_for_end_row = 0;
 9556        let has_multiple_rows = start_row + 1 != end_row;
 9557        for row in start_row..end_row {
 9558            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9559            let indent_delta = match (current_indent.kind, indent_kind) {
 9560                (IndentKind::Space, IndentKind::Space) => {
 9561                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9562                    IndentSize::spaces(columns_to_next_tab_stop)
 9563                }
 9564                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9565                (_, IndentKind::Tab) => IndentSize::tab(),
 9566            };
 9567
 9568            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9569                0
 9570            } else {
 9571                selection.start.column
 9572            };
 9573            let row_start = Point::new(row, start);
 9574            edits.push((
 9575                row_start..row_start,
 9576                indent_delta.chars().collect::<String>(),
 9577            ));
 9578
 9579            // Update this selection's endpoints to reflect the indentation.
 9580            if row == selection.start.row {
 9581                selection.start.column += indent_delta.len;
 9582            }
 9583            if row == selection.end.row {
 9584                selection.end.column += indent_delta.len;
 9585                delta_for_end_row = indent_delta.len;
 9586            }
 9587        }
 9588
 9589        if selection.start.row == selection.end.row {
 9590            delta_for_start_row + delta_for_end_row
 9591        } else {
 9592            delta_for_end_row
 9593        }
 9594    }
 9595
 9596    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9597        if self.read_only(cx) {
 9598            return;
 9599        }
 9600        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9601        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9602        let selections = self.selections.all::<Point>(cx);
 9603        let mut deletion_ranges = Vec::new();
 9604        let mut last_outdent = None;
 9605        {
 9606            let buffer = self.buffer.read(cx);
 9607            let snapshot = buffer.snapshot(cx);
 9608            for selection in &selections {
 9609                let settings = buffer.language_settings_at(selection.start, cx);
 9610                let tab_size = settings.tab_size.get();
 9611                let mut rows = selection.spanned_rows(false, &display_map);
 9612
 9613                // Avoid re-outdenting a row that has already been outdented by a
 9614                // previous selection.
 9615                if let Some(last_row) = last_outdent {
 9616                    if last_row == rows.start {
 9617                        rows.start = rows.start.next_row();
 9618                    }
 9619                }
 9620                let has_multiple_rows = rows.len() > 1;
 9621                for row in rows.iter_rows() {
 9622                    let indent_size = snapshot.indent_size_for_line(row);
 9623                    if indent_size.len > 0 {
 9624                        let deletion_len = match indent_size.kind {
 9625                            IndentKind::Space => {
 9626                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9627                                if columns_to_prev_tab_stop == 0 {
 9628                                    tab_size
 9629                                } else {
 9630                                    columns_to_prev_tab_stop
 9631                                }
 9632                            }
 9633                            IndentKind::Tab => 1,
 9634                        };
 9635                        let start = if has_multiple_rows
 9636                            || deletion_len > selection.start.column
 9637                            || indent_size.len < selection.start.column
 9638                        {
 9639                            0
 9640                        } else {
 9641                            selection.start.column - deletion_len
 9642                        };
 9643                        deletion_ranges.push(
 9644                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9645                        );
 9646                        last_outdent = Some(row);
 9647                    }
 9648                }
 9649            }
 9650        }
 9651
 9652        self.transact(window, cx, |this, window, cx| {
 9653            this.buffer.update(cx, |buffer, cx| {
 9654                let empty_str: Arc<str> = Arc::default();
 9655                buffer.edit(
 9656                    deletion_ranges
 9657                        .into_iter()
 9658                        .map(|range| (range, empty_str.clone())),
 9659                    None,
 9660                    cx,
 9661                );
 9662            });
 9663            let selections = this.selections.all::<usize>(cx);
 9664            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9665                s.select(selections)
 9666            });
 9667        });
 9668    }
 9669
 9670    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9671        if self.read_only(cx) {
 9672            return;
 9673        }
 9674        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9675        let selections = self
 9676            .selections
 9677            .all::<usize>(cx)
 9678            .into_iter()
 9679            .map(|s| s.range());
 9680
 9681        self.transact(window, cx, |this, window, cx| {
 9682            this.buffer.update(cx, |buffer, cx| {
 9683                buffer.autoindent_ranges(selections, cx);
 9684            });
 9685            let selections = this.selections.all::<usize>(cx);
 9686            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9687                s.select(selections)
 9688            });
 9689        });
 9690    }
 9691
 9692    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9693        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9695        let selections = self.selections.all::<Point>(cx);
 9696
 9697        let mut new_cursors = Vec::new();
 9698        let mut edit_ranges = Vec::new();
 9699        let mut selections = selections.iter().peekable();
 9700        while let Some(selection) = selections.next() {
 9701            let mut rows = selection.spanned_rows(false, &display_map);
 9702            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9703
 9704            // Accumulate contiguous regions of rows that we want to delete.
 9705            while let Some(next_selection) = selections.peek() {
 9706                let next_rows = next_selection.spanned_rows(false, &display_map);
 9707                if next_rows.start <= rows.end {
 9708                    rows.end = next_rows.end;
 9709                    selections.next().unwrap();
 9710                } else {
 9711                    break;
 9712                }
 9713            }
 9714
 9715            let buffer = &display_map.buffer_snapshot;
 9716            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9717            let edit_end;
 9718            let cursor_buffer_row;
 9719            if buffer.max_point().row >= rows.end.0 {
 9720                // If there's a line after the range, delete the \n from the end of the row range
 9721                // and position the cursor on the next line.
 9722                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9723                cursor_buffer_row = rows.end;
 9724            } else {
 9725                // If there isn't a line after the range, delete the \n from the line before the
 9726                // start of the row range and position the cursor there.
 9727                edit_start = edit_start.saturating_sub(1);
 9728                edit_end = buffer.len();
 9729                cursor_buffer_row = rows.start.previous_row();
 9730            }
 9731
 9732            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9733            *cursor.column_mut() =
 9734                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9735
 9736            new_cursors.push((
 9737                selection.id,
 9738                buffer.anchor_after(cursor.to_point(&display_map)),
 9739            ));
 9740            edit_ranges.push(edit_start..edit_end);
 9741        }
 9742
 9743        self.transact(window, cx, |this, window, cx| {
 9744            let buffer = this.buffer.update(cx, |buffer, cx| {
 9745                let empty_str: Arc<str> = Arc::default();
 9746                buffer.edit(
 9747                    edit_ranges
 9748                        .into_iter()
 9749                        .map(|range| (range, empty_str.clone())),
 9750                    None,
 9751                    cx,
 9752                );
 9753                buffer.snapshot(cx)
 9754            });
 9755            let new_selections = new_cursors
 9756                .into_iter()
 9757                .map(|(id, cursor)| {
 9758                    let cursor = cursor.to_point(&buffer);
 9759                    Selection {
 9760                        id,
 9761                        start: cursor,
 9762                        end: cursor,
 9763                        reversed: false,
 9764                        goal: SelectionGoal::None,
 9765                    }
 9766                })
 9767                .collect();
 9768
 9769            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9770                s.select(new_selections);
 9771            });
 9772        });
 9773    }
 9774
 9775    pub fn join_lines_impl(
 9776        &mut self,
 9777        insert_whitespace: bool,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) {
 9781        if self.read_only(cx) {
 9782            return;
 9783        }
 9784        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9785        for selection in self.selections.all::<Point>(cx) {
 9786            let start = MultiBufferRow(selection.start.row);
 9787            // Treat single line selections as if they include the next line. Otherwise this action
 9788            // would do nothing for single line selections individual cursors.
 9789            let end = if selection.start.row == selection.end.row {
 9790                MultiBufferRow(selection.start.row + 1)
 9791            } else {
 9792                MultiBufferRow(selection.end.row)
 9793            };
 9794
 9795            if let Some(last_row_range) = row_ranges.last_mut() {
 9796                if start <= last_row_range.end {
 9797                    last_row_range.end = end;
 9798                    continue;
 9799                }
 9800            }
 9801            row_ranges.push(start..end);
 9802        }
 9803
 9804        let snapshot = self.buffer.read(cx).snapshot(cx);
 9805        let mut cursor_positions = Vec::new();
 9806        for row_range in &row_ranges {
 9807            let anchor = snapshot.anchor_before(Point::new(
 9808                row_range.end.previous_row().0,
 9809                snapshot.line_len(row_range.end.previous_row()),
 9810            ));
 9811            cursor_positions.push(anchor..anchor);
 9812        }
 9813
 9814        self.transact(window, cx, |this, window, cx| {
 9815            for row_range in row_ranges.into_iter().rev() {
 9816                for row in row_range.iter_rows().rev() {
 9817                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9818                    let next_line_row = row.next_row();
 9819                    let indent = snapshot.indent_size_for_line(next_line_row);
 9820                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9821
 9822                    let replace =
 9823                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9824                            " "
 9825                        } else {
 9826                            ""
 9827                        };
 9828
 9829                    this.buffer.update(cx, |buffer, cx| {
 9830                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9831                    });
 9832                }
 9833            }
 9834
 9835            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9836                s.select_anchor_ranges(cursor_positions)
 9837            });
 9838        });
 9839    }
 9840
 9841    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9842        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9843        self.join_lines_impl(true, window, cx);
 9844    }
 9845
 9846    pub fn sort_lines_case_sensitive(
 9847        &mut self,
 9848        _: &SortLinesCaseSensitive,
 9849        window: &mut Window,
 9850        cx: &mut Context<Self>,
 9851    ) {
 9852        self.manipulate_lines(window, cx, |lines| lines.sort())
 9853    }
 9854
 9855    pub fn sort_lines_case_insensitive(
 9856        &mut self,
 9857        _: &SortLinesCaseInsensitive,
 9858        window: &mut Window,
 9859        cx: &mut Context<Self>,
 9860    ) {
 9861        self.manipulate_lines(window, cx, |lines| {
 9862            lines.sort_by_key(|line| line.to_lowercase())
 9863        })
 9864    }
 9865
 9866    pub fn unique_lines_case_insensitive(
 9867        &mut self,
 9868        _: &UniqueLinesCaseInsensitive,
 9869        window: &mut Window,
 9870        cx: &mut Context<Self>,
 9871    ) {
 9872        self.manipulate_lines(window, cx, |lines| {
 9873            let mut seen = HashSet::default();
 9874            lines.retain(|line| seen.insert(line.to_lowercase()));
 9875        })
 9876    }
 9877
 9878    pub fn unique_lines_case_sensitive(
 9879        &mut self,
 9880        _: &UniqueLinesCaseSensitive,
 9881        window: &mut Window,
 9882        cx: &mut Context<Self>,
 9883    ) {
 9884        self.manipulate_lines(window, cx, |lines| {
 9885            let mut seen = HashSet::default();
 9886            lines.retain(|line| seen.insert(*line));
 9887        })
 9888    }
 9889
 9890    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9891        let Some(project) = self.project.clone() else {
 9892            return;
 9893        };
 9894        self.reload(project, window, cx)
 9895            .detach_and_notify_err(window, cx);
 9896    }
 9897
 9898    pub fn restore_file(
 9899        &mut self,
 9900        _: &::git::RestoreFile,
 9901        window: &mut Window,
 9902        cx: &mut Context<Self>,
 9903    ) {
 9904        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9905        let mut buffer_ids = HashSet::default();
 9906        let snapshot = self.buffer().read(cx).snapshot(cx);
 9907        for selection in self.selections.all::<usize>(cx) {
 9908            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9909        }
 9910
 9911        let buffer = self.buffer().read(cx);
 9912        let ranges = buffer_ids
 9913            .into_iter()
 9914            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9915            .collect::<Vec<_>>();
 9916
 9917        self.restore_hunks_in_ranges(ranges, window, cx);
 9918    }
 9919
 9920    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9921        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9922        let selections = self
 9923            .selections
 9924            .all(cx)
 9925            .into_iter()
 9926            .map(|s| s.range())
 9927            .collect();
 9928        self.restore_hunks_in_ranges(selections, window, cx);
 9929    }
 9930
 9931    pub fn restore_hunks_in_ranges(
 9932        &mut self,
 9933        ranges: Vec<Range<Point>>,
 9934        window: &mut Window,
 9935        cx: &mut Context<Editor>,
 9936    ) {
 9937        let mut revert_changes = HashMap::default();
 9938        let chunk_by = self
 9939            .snapshot(window, cx)
 9940            .hunks_for_ranges(ranges)
 9941            .into_iter()
 9942            .chunk_by(|hunk| hunk.buffer_id);
 9943        for (buffer_id, hunks) in &chunk_by {
 9944            let hunks = hunks.collect::<Vec<_>>();
 9945            for hunk in &hunks {
 9946                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9947            }
 9948            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9949        }
 9950        drop(chunk_by);
 9951        if !revert_changes.is_empty() {
 9952            self.transact(window, cx, |editor, window, cx| {
 9953                editor.restore(revert_changes, window, cx);
 9954            });
 9955        }
 9956    }
 9957
 9958    pub fn open_active_item_in_terminal(
 9959        &mut self,
 9960        _: &OpenInTerminal,
 9961        window: &mut Window,
 9962        cx: &mut Context<Self>,
 9963    ) {
 9964        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9965            let project_path = buffer.read(cx).project_path(cx)?;
 9966            let project = self.project.as_ref()?.read(cx);
 9967            let entry = project.entry_for_path(&project_path, cx)?;
 9968            let parent = match &entry.canonical_path {
 9969                Some(canonical_path) => canonical_path.to_path_buf(),
 9970                None => project.absolute_path(&project_path, cx)?,
 9971            }
 9972            .parent()?
 9973            .to_path_buf();
 9974            Some(parent)
 9975        }) {
 9976            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9977        }
 9978    }
 9979
 9980    fn set_breakpoint_context_menu(
 9981        &mut self,
 9982        display_row: DisplayRow,
 9983        position: Option<Anchor>,
 9984        clicked_point: gpui::Point<Pixels>,
 9985        window: &mut Window,
 9986        cx: &mut Context<Self>,
 9987    ) {
 9988        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9989            return;
 9990        }
 9991        let source = self
 9992            .buffer
 9993            .read(cx)
 9994            .snapshot(cx)
 9995            .anchor_before(Point::new(display_row.0, 0u32));
 9996
 9997        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9998
 9999        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10000            self,
10001            source,
10002            clicked_point,
10003            context_menu,
10004            window,
10005            cx,
10006        );
10007    }
10008
10009    fn add_edit_breakpoint_block(
10010        &mut self,
10011        anchor: Anchor,
10012        breakpoint: &Breakpoint,
10013        edit_action: BreakpointPromptEditAction,
10014        window: &mut Window,
10015        cx: &mut Context<Self>,
10016    ) {
10017        let weak_editor = cx.weak_entity();
10018        let bp_prompt = cx.new(|cx| {
10019            BreakpointPromptEditor::new(
10020                weak_editor,
10021                anchor,
10022                breakpoint.clone(),
10023                edit_action,
10024                window,
10025                cx,
10026            )
10027        });
10028
10029        let height = bp_prompt.update(cx, |this, cx| {
10030            this.prompt
10031                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10032        });
10033        let cloned_prompt = bp_prompt.clone();
10034        let blocks = vec![BlockProperties {
10035            style: BlockStyle::Sticky,
10036            placement: BlockPlacement::Above(anchor),
10037            height: Some(height),
10038            render: Arc::new(move |cx| {
10039                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10040                cloned_prompt.clone().into_any_element()
10041            }),
10042            priority: 0,
10043            render_in_minimap: true,
10044        }];
10045
10046        let focus_handle = bp_prompt.focus_handle(cx);
10047        window.focus(&focus_handle);
10048
10049        let block_ids = self.insert_blocks(blocks, None, cx);
10050        bp_prompt.update(cx, |prompt, _| {
10051            prompt.add_block_ids(block_ids);
10052        });
10053    }
10054
10055    pub(crate) fn breakpoint_at_row(
10056        &self,
10057        row: u32,
10058        window: &mut Window,
10059        cx: &mut Context<Self>,
10060    ) -> Option<(Anchor, Breakpoint)> {
10061        let snapshot = self.snapshot(window, cx);
10062        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10063
10064        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10065    }
10066
10067    pub(crate) fn breakpoint_at_anchor(
10068        &self,
10069        breakpoint_position: Anchor,
10070        snapshot: &EditorSnapshot,
10071        cx: &mut Context<Self>,
10072    ) -> Option<(Anchor, Breakpoint)> {
10073        let project = self.project.clone()?;
10074
10075        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10076            snapshot
10077                .buffer_snapshot
10078                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10079        })?;
10080
10081        let enclosing_excerpt = breakpoint_position.excerpt_id;
10082        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10083        let buffer_snapshot = buffer.read(cx).snapshot();
10084
10085        let row = buffer_snapshot
10086            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10087            .row;
10088
10089        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10090        let anchor_end = snapshot
10091            .buffer_snapshot
10092            .anchor_after(Point::new(row, line_len));
10093
10094        let bp = self
10095            .breakpoint_store
10096            .as_ref()?
10097            .read_with(cx, |breakpoint_store, cx| {
10098                breakpoint_store
10099                    .breakpoints(
10100                        &buffer,
10101                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10102                        &buffer_snapshot,
10103                        cx,
10104                    )
10105                    .next()
10106                    .and_then(|(bp, _)| {
10107                        let breakpoint_row = buffer_snapshot
10108                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10109                            .row;
10110
10111                        if breakpoint_row == row {
10112                            snapshot
10113                                .buffer_snapshot
10114                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10115                                .map(|position| (position, bp.bp.clone()))
10116                        } else {
10117                            None
10118                        }
10119                    })
10120            });
10121        bp
10122    }
10123
10124    pub fn edit_log_breakpoint(
10125        &mut self,
10126        _: &EditLogBreakpoint,
10127        window: &mut Window,
10128        cx: &mut Context<Self>,
10129    ) {
10130        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10131            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10132                message: None,
10133                state: BreakpointState::Enabled,
10134                condition: None,
10135                hit_condition: None,
10136            });
10137
10138            self.add_edit_breakpoint_block(
10139                anchor,
10140                &breakpoint,
10141                BreakpointPromptEditAction::Log,
10142                window,
10143                cx,
10144            );
10145        }
10146    }
10147
10148    fn breakpoints_at_cursors(
10149        &self,
10150        window: &mut Window,
10151        cx: &mut Context<Self>,
10152    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10153        let snapshot = self.snapshot(window, cx);
10154        let cursors = self
10155            .selections
10156            .disjoint_anchors()
10157            .into_iter()
10158            .map(|selection| {
10159                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10160
10161                let breakpoint_position = self
10162                    .breakpoint_at_row(cursor_position.row, window, cx)
10163                    .map(|bp| bp.0)
10164                    .unwrap_or_else(|| {
10165                        snapshot
10166                            .display_snapshot
10167                            .buffer_snapshot
10168                            .anchor_after(Point::new(cursor_position.row, 0))
10169                    });
10170
10171                let breakpoint = self
10172                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10173                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10174
10175                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10176            })
10177            // 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.
10178            .collect::<HashMap<Anchor, _>>();
10179
10180        cursors.into_iter().collect()
10181    }
10182
10183    pub fn enable_breakpoint(
10184        &mut self,
10185        _: &crate::actions::EnableBreakpoint,
10186        window: &mut Window,
10187        cx: &mut Context<Self>,
10188    ) {
10189        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10190            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10191                continue;
10192            };
10193            self.edit_breakpoint_at_anchor(
10194                anchor,
10195                breakpoint,
10196                BreakpointEditAction::InvertState,
10197                cx,
10198            );
10199        }
10200    }
10201
10202    pub fn disable_breakpoint(
10203        &mut self,
10204        _: &crate::actions::DisableBreakpoint,
10205        window: &mut Window,
10206        cx: &mut Context<Self>,
10207    ) {
10208        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10209            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10210                continue;
10211            };
10212            self.edit_breakpoint_at_anchor(
10213                anchor,
10214                breakpoint,
10215                BreakpointEditAction::InvertState,
10216                cx,
10217            );
10218        }
10219    }
10220
10221    pub fn toggle_breakpoint(
10222        &mut self,
10223        _: &crate::actions::ToggleBreakpoint,
10224        window: &mut Window,
10225        cx: &mut Context<Self>,
10226    ) {
10227        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10228            if let Some(breakpoint) = breakpoint {
10229                self.edit_breakpoint_at_anchor(
10230                    anchor,
10231                    breakpoint,
10232                    BreakpointEditAction::Toggle,
10233                    cx,
10234                );
10235            } else {
10236                self.edit_breakpoint_at_anchor(
10237                    anchor,
10238                    Breakpoint::new_standard(),
10239                    BreakpointEditAction::Toggle,
10240                    cx,
10241                );
10242            }
10243        }
10244    }
10245
10246    pub fn edit_breakpoint_at_anchor(
10247        &mut self,
10248        breakpoint_position: Anchor,
10249        breakpoint: Breakpoint,
10250        edit_action: BreakpointEditAction,
10251        cx: &mut Context<Self>,
10252    ) {
10253        let Some(breakpoint_store) = &self.breakpoint_store else {
10254            return;
10255        };
10256
10257        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10258            if breakpoint_position == Anchor::min() {
10259                self.buffer()
10260                    .read(cx)
10261                    .excerpt_buffer_ids()
10262                    .into_iter()
10263                    .next()
10264            } else {
10265                None
10266            }
10267        }) else {
10268            return;
10269        };
10270
10271        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10272            return;
10273        };
10274
10275        breakpoint_store.update(cx, |breakpoint_store, cx| {
10276            breakpoint_store.toggle_breakpoint(
10277                buffer,
10278                BreakpointWithPosition {
10279                    position: breakpoint_position.text_anchor,
10280                    bp: breakpoint,
10281                },
10282                edit_action,
10283                cx,
10284            );
10285        });
10286
10287        cx.notify();
10288    }
10289
10290    #[cfg(any(test, feature = "test-support"))]
10291    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10292        self.breakpoint_store.clone()
10293    }
10294
10295    pub fn prepare_restore_change(
10296        &self,
10297        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10298        hunk: &MultiBufferDiffHunk,
10299        cx: &mut App,
10300    ) -> Option<()> {
10301        if hunk.is_created_file() {
10302            return None;
10303        }
10304        let buffer = self.buffer.read(cx);
10305        let diff = buffer.diff_for(hunk.buffer_id)?;
10306        let buffer = buffer.buffer(hunk.buffer_id)?;
10307        let buffer = buffer.read(cx);
10308        let original_text = diff
10309            .read(cx)
10310            .base_text()
10311            .as_rope()
10312            .slice(hunk.diff_base_byte_range.clone());
10313        let buffer_snapshot = buffer.snapshot();
10314        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10315        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10316            probe
10317                .0
10318                .start
10319                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10320                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10321        }) {
10322            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10323            Some(())
10324        } else {
10325            None
10326        }
10327    }
10328
10329    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10330        self.manipulate_lines(window, cx, |lines| lines.reverse())
10331    }
10332
10333    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10334        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10335    }
10336
10337    fn manipulate_lines<Fn>(
10338        &mut self,
10339        window: &mut Window,
10340        cx: &mut Context<Self>,
10341        mut callback: Fn,
10342    ) where
10343        Fn: FnMut(&mut Vec<&str>),
10344    {
10345        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10346
10347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10348        let buffer = self.buffer.read(cx).snapshot(cx);
10349
10350        let mut edits = Vec::new();
10351
10352        let selections = self.selections.all::<Point>(cx);
10353        let mut selections = selections.iter().peekable();
10354        let mut contiguous_row_selections = Vec::new();
10355        let mut new_selections = Vec::new();
10356        let mut added_lines = 0;
10357        let mut removed_lines = 0;
10358
10359        while let Some(selection) = selections.next() {
10360            let (start_row, end_row) = consume_contiguous_rows(
10361                &mut contiguous_row_selections,
10362                selection,
10363                &display_map,
10364                &mut selections,
10365            );
10366
10367            let start_point = Point::new(start_row.0, 0);
10368            let end_point = Point::new(
10369                end_row.previous_row().0,
10370                buffer.line_len(end_row.previous_row()),
10371            );
10372            let text = buffer
10373                .text_for_range(start_point..end_point)
10374                .collect::<String>();
10375
10376            let mut lines = text.split('\n').collect_vec();
10377
10378            let lines_before = lines.len();
10379            callback(&mut lines);
10380            let lines_after = lines.len();
10381
10382            edits.push((start_point..end_point, lines.join("\n")));
10383
10384            // Selections must change based on added and removed line count
10385            let start_row =
10386                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10387            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10388            new_selections.push(Selection {
10389                id: selection.id,
10390                start: start_row,
10391                end: end_row,
10392                goal: SelectionGoal::None,
10393                reversed: selection.reversed,
10394            });
10395
10396            if lines_after > lines_before {
10397                added_lines += lines_after - lines_before;
10398            } else if lines_before > lines_after {
10399                removed_lines += lines_before - lines_after;
10400            }
10401        }
10402
10403        self.transact(window, cx, |this, window, cx| {
10404            let buffer = this.buffer.update(cx, |buffer, cx| {
10405                buffer.edit(edits, None, cx);
10406                buffer.snapshot(cx)
10407            });
10408
10409            // Recalculate offsets on newly edited buffer
10410            let new_selections = new_selections
10411                .iter()
10412                .map(|s| {
10413                    let start_point = Point::new(s.start.0, 0);
10414                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10415                    Selection {
10416                        id: s.id,
10417                        start: buffer.point_to_offset(start_point),
10418                        end: buffer.point_to_offset(end_point),
10419                        goal: s.goal,
10420                        reversed: s.reversed,
10421                    }
10422                })
10423                .collect();
10424
10425            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10426                s.select(new_selections);
10427            });
10428
10429            this.request_autoscroll(Autoscroll::fit(), cx);
10430        });
10431    }
10432
10433    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10434        self.manipulate_text(window, cx, |text| {
10435            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10436            if has_upper_case_characters {
10437                text.to_lowercase()
10438            } else {
10439                text.to_uppercase()
10440            }
10441        })
10442    }
10443
10444    pub fn convert_to_upper_case(
10445        &mut self,
10446        _: &ConvertToUpperCase,
10447        window: &mut Window,
10448        cx: &mut Context<Self>,
10449    ) {
10450        self.manipulate_text(window, cx, |text| text.to_uppercase())
10451    }
10452
10453    pub fn convert_to_lower_case(
10454        &mut self,
10455        _: &ConvertToLowerCase,
10456        window: &mut Window,
10457        cx: &mut Context<Self>,
10458    ) {
10459        self.manipulate_text(window, cx, |text| text.to_lowercase())
10460    }
10461
10462    pub fn convert_to_title_case(
10463        &mut self,
10464        _: &ConvertToTitleCase,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        self.manipulate_text(window, cx, |text| {
10469            text.split('\n')
10470                .map(|line| line.to_case(Case::Title))
10471                .join("\n")
10472        })
10473    }
10474
10475    pub fn convert_to_snake_case(
10476        &mut self,
10477        _: &ConvertToSnakeCase,
10478        window: &mut Window,
10479        cx: &mut Context<Self>,
10480    ) {
10481        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10482    }
10483
10484    pub fn convert_to_kebab_case(
10485        &mut self,
10486        _: &ConvertToKebabCase,
10487        window: &mut Window,
10488        cx: &mut Context<Self>,
10489    ) {
10490        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10491    }
10492
10493    pub fn convert_to_upper_camel_case(
10494        &mut self,
10495        _: &ConvertToUpperCamelCase,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_text(window, cx, |text| {
10500            text.split('\n')
10501                .map(|line| line.to_case(Case::UpperCamel))
10502                .join("\n")
10503        })
10504    }
10505
10506    pub fn convert_to_lower_camel_case(
10507        &mut self,
10508        _: &ConvertToLowerCamelCase,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10513    }
10514
10515    pub fn convert_to_opposite_case(
10516        &mut self,
10517        _: &ConvertToOppositeCase,
10518        window: &mut Window,
10519        cx: &mut Context<Self>,
10520    ) {
10521        self.manipulate_text(window, cx, |text| {
10522            text.chars()
10523                .fold(String::with_capacity(text.len()), |mut t, c| {
10524                    if c.is_uppercase() {
10525                        t.extend(c.to_lowercase());
10526                    } else {
10527                        t.extend(c.to_uppercase());
10528                    }
10529                    t
10530                })
10531        })
10532    }
10533
10534    pub fn convert_to_rot13(
10535        &mut self,
10536        _: &ConvertToRot13,
10537        window: &mut Window,
10538        cx: &mut Context<Self>,
10539    ) {
10540        self.manipulate_text(window, cx, |text| {
10541            text.chars()
10542                .map(|c| match c {
10543                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10544                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10545                    _ => c,
10546                })
10547                .collect()
10548        })
10549    }
10550
10551    pub fn convert_to_rot47(
10552        &mut self,
10553        _: &ConvertToRot47,
10554        window: &mut Window,
10555        cx: &mut Context<Self>,
10556    ) {
10557        self.manipulate_text(window, cx, |text| {
10558            text.chars()
10559                .map(|c| {
10560                    let code_point = c as u32;
10561                    if code_point >= 33 && code_point <= 126 {
10562                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10563                    }
10564                    c
10565                })
10566                .collect()
10567        })
10568    }
10569
10570    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10571    where
10572        Fn: FnMut(&str) -> String,
10573    {
10574        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10575        let buffer = self.buffer.read(cx).snapshot(cx);
10576
10577        let mut new_selections = Vec::new();
10578        let mut edits = Vec::new();
10579        let mut selection_adjustment = 0i32;
10580
10581        for selection in self.selections.all::<usize>(cx) {
10582            let selection_is_empty = selection.is_empty();
10583
10584            let (start, end) = if selection_is_empty {
10585                let word_range = movement::surrounding_word(
10586                    &display_map,
10587                    selection.start.to_display_point(&display_map),
10588                );
10589                let start = word_range.start.to_offset(&display_map, Bias::Left);
10590                let end = word_range.end.to_offset(&display_map, Bias::Left);
10591                (start, end)
10592            } else {
10593                (selection.start, selection.end)
10594            };
10595
10596            let text = buffer.text_for_range(start..end).collect::<String>();
10597            let old_length = text.len() as i32;
10598            let text = callback(&text);
10599
10600            new_selections.push(Selection {
10601                start: (start as i32 - selection_adjustment) as usize,
10602                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10603                goal: SelectionGoal::None,
10604                ..selection
10605            });
10606
10607            selection_adjustment += old_length - text.len() as i32;
10608
10609            edits.push((start..end, text));
10610        }
10611
10612        self.transact(window, cx, |this, window, cx| {
10613            this.buffer.update(cx, |buffer, cx| {
10614                buffer.edit(edits, None, cx);
10615            });
10616
10617            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10618                s.select(new_selections);
10619            });
10620
10621            this.request_autoscroll(Autoscroll::fit(), cx);
10622        });
10623    }
10624
10625    pub fn move_selection_on_drop(
10626        &mut self,
10627        selection: &Selection<Anchor>,
10628        target: DisplayPoint,
10629        is_cut: bool,
10630        window: &mut Window,
10631        cx: &mut Context<Self>,
10632    ) {
10633        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10634        let buffer = &display_map.buffer_snapshot;
10635        let mut edits = Vec::new();
10636        let insert_point = display_map
10637            .clip_point(target, Bias::Left)
10638            .to_point(&display_map);
10639        let text = buffer
10640            .text_for_range(selection.start..selection.end)
10641            .collect::<String>();
10642        if is_cut {
10643            edits.push(((selection.start..selection.end), String::new()));
10644        }
10645        let insert_anchor = buffer.anchor_before(insert_point);
10646        edits.push(((insert_anchor..insert_anchor), text));
10647        let last_edit_start = insert_anchor.bias_left(buffer);
10648        let last_edit_end = insert_anchor.bias_right(buffer);
10649        self.transact(window, cx, |this, window, cx| {
10650            this.buffer.update(cx, |buffer, cx| {
10651                buffer.edit(edits, None, cx);
10652            });
10653            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10654                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10655            });
10656        });
10657    }
10658
10659    pub fn clear_selection_drag_state(&mut self) {
10660        self.selection_drag_state = SelectionDragState::None;
10661    }
10662
10663    pub fn duplicate(
10664        &mut self,
10665        upwards: bool,
10666        whole_lines: bool,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10671
10672        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10673        let buffer = &display_map.buffer_snapshot;
10674        let selections = self.selections.all::<Point>(cx);
10675
10676        let mut edits = Vec::new();
10677        let mut selections_iter = selections.iter().peekable();
10678        while let Some(selection) = selections_iter.next() {
10679            let mut rows = selection.spanned_rows(false, &display_map);
10680            // duplicate line-wise
10681            if whole_lines || selection.start == selection.end {
10682                // Avoid duplicating the same lines twice.
10683                while let Some(next_selection) = selections_iter.peek() {
10684                    let next_rows = next_selection.spanned_rows(false, &display_map);
10685                    if next_rows.start < rows.end {
10686                        rows.end = next_rows.end;
10687                        selections_iter.next().unwrap();
10688                    } else {
10689                        break;
10690                    }
10691                }
10692
10693                // Copy the text from the selected row region and splice it either at the start
10694                // or end of the region.
10695                let start = Point::new(rows.start.0, 0);
10696                let end = Point::new(
10697                    rows.end.previous_row().0,
10698                    buffer.line_len(rows.end.previous_row()),
10699                );
10700                let text = buffer
10701                    .text_for_range(start..end)
10702                    .chain(Some("\n"))
10703                    .collect::<String>();
10704                let insert_location = if upwards {
10705                    Point::new(rows.end.0, 0)
10706                } else {
10707                    start
10708                };
10709                edits.push((insert_location..insert_location, text));
10710            } else {
10711                // duplicate character-wise
10712                let start = selection.start;
10713                let end = selection.end;
10714                let text = buffer.text_for_range(start..end).collect::<String>();
10715                edits.push((selection.end..selection.end, text));
10716            }
10717        }
10718
10719        self.transact(window, cx, |this, _, cx| {
10720            this.buffer.update(cx, |buffer, cx| {
10721                buffer.edit(edits, None, cx);
10722            });
10723
10724            this.request_autoscroll(Autoscroll::fit(), cx);
10725        });
10726    }
10727
10728    pub fn duplicate_line_up(
10729        &mut self,
10730        _: &DuplicateLineUp,
10731        window: &mut Window,
10732        cx: &mut Context<Self>,
10733    ) {
10734        self.duplicate(true, true, window, cx);
10735    }
10736
10737    pub fn duplicate_line_down(
10738        &mut self,
10739        _: &DuplicateLineDown,
10740        window: &mut Window,
10741        cx: &mut Context<Self>,
10742    ) {
10743        self.duplicate(false, true, window, cx);
10744    }
10745
10746    pub fn duplicate_selection(
10747        &mut self,
10748        _: &DuplicateSelection,
10749        window: &mut Window,
10750        cx: &mut Context<Self>,
10751    ) {
10752        self.duplicate(false, false, window, cx);
10753    }
10754
10755    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10756        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10757
10758        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10759        let buffer = self.buffer.read(cx).snapshot(cx);
10760
10761        let mut edits = Vec::new();
10762        let mut unfold_ranges = Vec::new();
10763        let mut refold_creases = Vec::new();
10764
10765        let selections = self.selections.all::<Point>(cx);
10766        let mut selections = selections.iter().peekable();
10767        let mut contiguous_row_selections = Vec::new();
10768        let mut new_selections = Vec::new();
10769
10770        while let Some(selection) = selections.next() {
10771            // Find all the selections that span a contiguous row range
10772            let (start_row, end_row) = consume_contiguous_rows(
10773                &mut contiguous_row_selections,
10774                selection,
10775                &display_map,
10776                &mut selections,
10777            );
10778
10779            // Move the text spanned by the row range to be before the line preceding the row range
10780            if start_row.0 > 0 {
10781                let range_to_move = Point::new(
10782                    start_row.previous_row().0,
10783                    buffer.line_len(start_row.previous_row()),
10784                )
10785                    ..Point::new(
10786                        end_row.previous_row().0,
10787                        buffer.line_len(end_row.previous_row()),
10788                    );
10789                let insertion_point = display_map
10790                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10791                    .0;
10792
10793                // Don't move lines across excerpts
10794                if buffer
10795                    .excerpt_containing(insertion_point..range_to_move.end)
10796                    .is_some()
10797                {
10798                    let text = buffer
10799                        .text_for_range(range_to_move.clone())
10800                        .flat_map(|s| s.chars())
10801                        .skip(1)
10802                        .chain(['\n'])
10803                        .collect::<String>();
10804
10805                    edits.push((
10806                        buffer.anchor_after(range_to_move.start)
10807                            ..buffer.anchor_before(range_to_move.end),
10808                        String::new(),
10809                    ));
10810                    let insertion_anchor = buffer.anchor_after(insertion_point);
10811                    edits.push((insertion_anchor..insertion_anchor, text));
10812
10813                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10814
10815                    // Move selections up
10816                    new_selections.extend(contiguous_row_selections.drain(..).map(
10817                        |mut selection| {
10818                            selection.start.row -= row_delta;
10819                            selection.end.row -= row_delta;
10820                            selection
10821                        },
10822                    ));
10823
10824                    // Move folds up
10825                    unfold_ranges.push(range_to_move.clone());
10826                    for fold in display_map.folds_in_range(
10827                        buffer.anchor_before(range_to_move.start)
10828                            ..buffer.anchor_after(range_to_move.end),
10829                    ) {
10830                        let mut start = fold.range.start.to_point(&buffer);
10831                        let mut end = fold.range.end.to_point(&buffer);
10832                        start.row -= row_delta;
10833                        end.row -= row_delta;
10834                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10835                    }
10836                }
10837            }
10838
10839            // If we didn't move line(s), preserve the existing selections
10840            new_selections.append(&mut contiguous_row_selections);
10841        }
10842
10843        self.transact(window, cx, |this, window, cx| {
10844            this.unfold_ranges(&unfold_ranges, true, true, cx);
10845            this.buffer.update(cx, |buffer, cx| {
10846                for (range, text) in edits {
10847                    buffer.edit([(range, text)], None, cx);
10848                }
10849            });
10850            this.fold_creases(refold_creases, true, window, cx);
10851            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10852                s.select(new_selections);
10853            })
10854        });
10855    }
10856
10857    pub fn move_line_down(
10858        &mut self,
10859        _: &MoveLineDown,
10860        window: &mut Window,
10861        cx: &mut Context<Self>,
10862    ) {
10863        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10864
10865        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10866        let buffer = self.buffer.read(cx).snapshot(cx);
10867
10868        let mut edits = Vec::new();
10869        let mut unfold_ranges = Vec::new();
10870        let mut refold_creases = Vec::new();
10871
10872        let selections = self.selections.all::<Point>(cx);
10873        let mut selections = selections.iter().peekable();
10874        let mut contiguous_row_selections = Vec::new();
10875        let mut new_selections = Vec::new();
10876
10877        while let Some(selection) = selections.next() {
10878            // Find all the selections that span a contiguous row range
10879            let (start_row, end_row) = consume_contiguous_rows(
10880                &mut contiguous_row_selections,
10881                selection,
10882                &display_map,
10883                &mut selections,
10884            );
10885
10886            // Move the text spanned by the row range to be after the last line of the row range
10887            if end_row.0 <= buffer.max_point().row {
10888                let range_to_move =
10889                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10890                let insertion_point = display_map
10891                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10892                    .0;
10893
10894                // Don't move lines across excerpt boundaries
10895                if buffer
10896                    .excerpt_containing(range_to_move.start..insertion_point)
10897                    .is_some()
10898                {
10899                    let mut text = String::from("\n");
10900                    text.extend(buffer.text_for_range(range_to_move.clone()));
10901                    text.pop(); // Drop trailing newline
10902                    edits.push((
10903                        buffer.anchor_after(range_to_move.start)
10904                            ..buffer.anchor_before(range_to_move.end),
10905                        String::new(),
10906                    ));
10907                    let insertion_anchor = buffer.anchor_after(insertion_point);
10908                    edits.push((insertion_anchor..insertion_anchor, text));
10909
10910                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10911
10912                    // Move selections down
10913                    new_selections.extend(contiguous_row_selections.drain(..).map(
10914                        |mut selection| {
10915                            selection.start.row += row_delta;
10916                            selection.end.row += row_delta;
10917                            selection
10918                        },
10919                    ));
10920
10921                    // Move folds down
10922                    unfold_ranges.push(range_to_move.clone());
10923                    for fold in display_map.folds_in_range(
10924                        buffer.anchor_before(range_to_move.start)
10925                            ..buffer.anchor_after(range_to_move.end),
10926                    ) {
10927                        let mut start = fold.range.start.to_point(&buffer);
10928                        let mut end = fold.range.end.to_point(&buffer);
10929                        start.row += row_delta;
10930                        end.row += row_delta;
10931                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10932                    }
10933                }
10934            }
10935
10936            // If we didn't move line(s), preserve the existing selections
10937            new_selections.append(&mut contiguous_row_selections);
10938        }
10939
10940        self.transact(window, cx, |this, window, cx| {
10941            this.unfold_ranges(&unfold_ranges, true, true, cx);
10942            this.buffer.update(cx, |buffer, cx| {
10943                for (range, text) in edits {
10944                    buffer.edit([(range, text)], None, cx);
10945                }
10946            });
10947            this.fold_creases(refold_creases, true, window, cx);
10948            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10949                s.select(new_selections)
10950            });
10951        });
10952    }
10953
10954    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10955        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10956        let text_layout_details = &self.text_layout_details(window);
10957        self.transact(window, cx, |this, window, cx| {
10958            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10959                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10960                s.move_with(|display_map, selection| {
10961                    if !selection.is_empty() {
10962                        return;
10963                    }
10964
10965                    let mut head = selection.head();
10966                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10967                    if head.column() == display_map.line_len(head.row()) {
10968                        transpose_offset = display_map
10969                            .buffer_snapshot
10970                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10971                    }
10972
10973                    if transpose_offset == 0 {
10974                        return;
10975                    }
10976
10977                    *head.column_mut() += 1;
10978                    head = display_map.clip_point(head, Bias::Right);
10979                    let goal = SelectionGoal::HorizontalPosition(
10980                        display_map
10981                            .x_for_display_point(head, text_layout_details)
10982                            .into(),
10983                    );
10984                    selection.collapse_to(head, goal);
10985
10986                    let transpose_start = display_map
10987                        .buffer_snapshot
10988                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10989                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10990                        let transpose_end = display_map
10991                            .buffer_snapshot
10992                            .clip_offset(transpose_offset + 1, Bias::Right);
10993                        if let Some(ch) =
10994                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10995                        {
10996                            edits.push((transpose_start..transpose_offset, String::new()));
10997                            edits.push((transpose_end..transpose_end, ch.to_string()));
10998                        }
10999                    }
11000                });
11001                edits
11002            });
11003            this.buffer
11004                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11005            let selections = this.selections.all::<usize>(cx);
11006            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11007                s.select(selections);
11008            });
11009        });
11010    }
11011
11012    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11013        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11014        self.rewrap_impl(RewrapOptions::default(), cx)
11015    }
11016
11017    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11018        let buffer = self.buffer.read(cx).snapshot(cx);
11019        let selections = self.selections.all::<Point>(cx);
11020
11021        // Shrink and split selections to respect paragraph boundaries.
11022        let ranges = selections.into_iter().flat_map(|selection| {
11023            let language_settings = buffer.language_settings_at(selection.head(), cx);
11024            let language_scope = buffer.language_scope_at(selection.head());
11025
11026            let Some(start_row) = (selection.start.row..=selection.end.row)
11027                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11028            else {
11029                return vec![];
11030            };
11031            let Some(end_row) = (selection.start.row..=selection.end.row)
11032                .rev()
11033                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11034            else {
11035                return vec![];
11036            };
11037
11038            let mut row = start_row;
11039            let mut ranges = Vec::new();
11040            while let Some(blank_row) =
11041                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11042            {
11043                let next_paragraph_start = (blank_row + 1..=end_row)
11044                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11045                    .unwrap();
11046                ranges.push((
11047                    language_settings.clone(),
11048                    language_scope.clone(),
11049                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11050                ));
11051                row = next_paragraph_start;
11052            }
11053            ranges.push((
11054                language_settings.clone(),
11055                language_scope.clone(),
11056                Point::new(row, 0)..Point::new(end_row, 0),
11057            ));
11058
11059            ranges
11060        });
11061
11062        let mut edits = Vec::new();
11063        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11064
11065        for (language_settings, language_scope, range) in ranges {
11066            let mut start_row = range.start.row;
11067            let mut end_row = range.end.row;
11068
11069            // Skip selections that overlap with a range that has already been rewrapped.
11070            let selection_range = start_row..end_row;
11071            if rewrapped_row_ranges
11072                .iter()
11073                .any(|range| range.overlaps(&selection_range))
11074            {
11075                continue;
11076            }
11077
11078            let tab_size = language_settings.tab_size;
11079
11080            // Since not all lines in the selection may be at the same indent
11081            // level, choose the indent size that is the most common between all
11082            // of the lines.
11083            //
11084            // If there is a tie, we use the deepest indent.
11085            let (indent_size, indent_end) = {
11086                let mut indent_size_occurrences = HashMap::default();
11087                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11088
11089                for row in start_row..=end_row {
11090                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11091                    rows_by_indent_size.entry(indent).or_default().push(row);
11092                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11093                }
11094
11095                let indent_size = indent_size_occurrences
11096                    .into_iter()
11097                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11098                    .map(|(indent, _)| indent)
11099                    .unwrap_or_default();
11100                let row = rows_by_indent_size[&indent_size][0];
11101                let indent_end = Point::new(row, indent_size.len);
11102
11103                (indent_size, indent_end)
11104            };
11105
11106            let mut line_prefix = indent_size.chars().collect::<String>();
11107
11108            let mut inside_comment = false;
11109            if let Some(comment_prefix) = language_scope.and_then(|language| {
11110                language
11111                    .line_comment_prefixes()
11112                    .iter()
11113                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11114                    .cloned()
11115            }) {
11116                line_prefix.push_str(&comment_prefix);
11117                inside_comment = true;
11118            }
11119
11120            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11121                RewrapBehavior::InComments => inside_comment,
11122                RewrapBehavior::InSelections => !range.is_empty(),
11123                RewrapBehavior::Anywhere => true,
11124            };
11125
11126            let should_rewrap = options.override_language_settings
11127                || allow_rewrap_based_on_language
11128                || self.hard_wrap.is_some();
11129            if !should_rewrap {
11130                continue;
11131            }
11132
11133            if range.is_empty() {
11134                'expand_upwards: while start_row > 0 {
11135                    let prev_row = start_row - 1;
11136                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11137                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11138                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11139                    {
11140                        start_row = prev_row;
11141                    } else {
11142                        break 'expand_upwards;
11143                    }
11144                }
11145
11146                'expand_downwards: while end_row < buffer.max_point().row {
11147                    let next_row = end_row + 1;
11148                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11149                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11150                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11151                    {
11152                        end_row = next_row;
11153                    } else {
11154                        break 'expand_downwards;
11155                    }
11156                }
11157            }
11158
11159            let start = Point::new(start_row, 0);
11160            let start_offset = start.to_offset(&buffer);
11161            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11162            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11163            let Some(lines_without_prefixes) = selection_text
11164                .lines()
11165                .map(|line| {
11166                    line.strip_prefix(&line_prefix)
11167                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11168                        .with_context(|| {
11169                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11170                        })
11171                })
11172                .collect::<Result<Vec<_>, _>>()
11173                .log_err()
11174            else {
11175                continue;
11176            };
11177
11178            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11179                buffer
11180                    .language_settings_at(Point::new(start_row, 0), cx)
11181                    .preferred_line_length as usize
11182            });
11183            let wrapped_text = wrap_with_prefix(
11184                line_prefix,
11185                lines_without_prefixes.join("\n"),
11186                wrap_column,
11187                tab_size,
11188                options.preserve_existing_whitespace,
11189            );
11190
11191            // TODO: should always use char-based diff while still supporting cursor behavior that
11192            // matches vim.
11193            let mut diff_options = DiffOptions::default();
11194            if options.override_language_settings {
11195                diff_options.max_word_diff_len = 0;
11196                diff_options.max_word_diff_line_count = 0;
11197            } else {
11198                diff_options.max_word_diff_len = usize::MAX;
11199                diff_options.max_word_diff_line_count = usize::MAX;
11200            }
11201
11202            for (old_range, new_text) in
11203                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11204            {
11205                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11206                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11207                edits.push((edit_start..edit_end, new_text));
11208            }
11209
11210            rewrapped_row_ranges.push(start_row..=end_row);
11211        }
11212
11213        self.buffer
11214            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11215    }
11216
11217    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11218        let mut text = String::new();
11219        let buffer = self.buffer.read(cx).snapshot(cx);
11220        let mut selections = self.selections.all::<Point>(cx);
11221        let mut clipboard_selections = Vec::with_capacity(selections.len());
11222        {
11223            let max_point = buffer.max_point();
11224            let mut is_first = true;
11225            for selection in &mut selections {
11226                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11227                if is_entire_line {
11228                    selection.start = Point::new(selection.start.row, 0);
11229                    if !selection.is_empty() && selection.end.column == 0 {
11230                        selection.end = cmp::min(max_point, selection.end);
11231                    } else {
11232                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11233                    }
11234                    selection.goal = SelectionGoal::None;
11235                }
11236                if is_first {
11237                    is_first = false;
11238                } else {
11239                    text += "\n";
11240                }
11241                let mut len = 0;
11242                for chunk in buffer.text_for_range(selection.start..selection.end) {
11243                    text.push_str(chunk);
11244                    len += chunk.len();
11245                }
11246                clipboard_selections.push(ClipboardSelection {
11247                    len,
11248                    is_entire_line,
11249                    first_line_indent: buffer
11250                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11251                        .len,
11252                });
11253            }
11254        }
11255
11256        self.transact(window, cx, |this, window, cx| {
11257            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11258                s.select(selections);
11259            });
11260            this.insert("", window, cx);
11261        });
11262        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11263    }
11264
11265    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11266        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11267        let item = self.cut_common(window, cx);
11268        cx.write_to_clipboard(item);
11269    }
11270
11271    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11272        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11273        self.change_selections(None, window, cx, |s| {
11274            s.move_with(|snapshot, sel| {
11275                if sel.is_empty() {
11276                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11277                }
11278            });
11279        });
11280        let item = self.cut_common(window, cx);
11281        cx.set_global(KillRing(item))
11282    }
11283
11284    pub fn kill_ring_yank(
11285        &mut self,
11286        _: &KillRingYank,
11287        window: &mut Window,
11288        cx: &mut Context<Self>,
11289    ) {
11290        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11291        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11292            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11293                (kill_ring.text().to_string(), kill_ring.metadata_json())
11294            } else {
11295                return;
11296            }
11297        } else {
11298            return;
11299        };
11300        self.do_paste(&text, metadata, false, window, cx);
11301    }
11302
11303    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11304        self.do_copy(true, cx);
11305    }
11306
11307    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11308        self.do_copy(false, cx);
11309    }
11310
11311    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11312        let selections = self.selections.all::<Point>(cx);
11313        let buffer = self.buffer.read(cx).read(cx);
11314        let mut text = String::new();
11315
11316        let mut clipboard_selections = Vec::with_capacity(selections.len());
11317        {
11318            let max_point = buffer.max_point();
11319            let mut is_first = true;
11320            for selection in &selections {
11321                let mut start = selection.start;
11322                let mut end = selection.end;
11323                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11324                if is_entire_line {
11325                    start = Point::new(start.row, 0);
11326                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11327                }
11328
11329                let mut trimmed_selections = Vec::new();
11330                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11331                    let row = MultiBufferRow(start.row);
11332                    let first_indent = buffer.indent_size_for_line(row);
11333                    if first_indent.len == 0 || start.column > first_indent.len {
11334                        trimmed_selections.push(start..end);
11335                    } else {
11336                        trimmed_selections.push(
11337                            Point::new(row.0, first_indent.len)
11338                                ..Point::new(row.0, buffer.line_len(row)),
11339                        );
11340                        for row in start.row + 1..=end.row {
11341                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11342                            if row == end.row {
11343                                line_len = end.column;
11344                            }
11345                            if line_len == 0 {
11346                                trimmed_selections
11347                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11348                                continue;
11349                            }
11350                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11351                            if row_indent_size.len >= first_indent.len {
11352                                trimmed_selections.push(
11353                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11354                                );
11355                            } else {
11356                                trimmed_selections.clear();
11357                                trimmed_selections.push(start..end);
11358                                break;
11359                            }
11360                        }
11361                    }
11362                } else {
11363                    trimmed_selections.push(start..end);
11364                }
11365
11366                for trimmed_range in trimmed_selections {
11367                    if is_first {
11368                        is_first = false;
11369                    } else {
11370                        text += "\n";
11371                    }
11372                    let mut len = 0;
11373                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11374                        text.push_str(chunk);
11375                        len += chunk.len();
11376                    }
11377                    clipboard_selections.push(ClipboardSelection {
11378                        len,
11379                        is_entire_line,
11380                        first_line_indent: buffer
11381                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11382                            .len,
11383                    });
11384                }
11385            }
11386        }
11387
11388        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11389            text,
11390            clipboard_selections,
11391        ));
11392    }
11393
11394    pub fn do_paste(
11395        &mut self,
11396        text: &String,
11397        clipboard_selections: Option<Vec<ClipboardSelection>>,
11398        handle_entire_lines: bool,
11399        window: &mut Window,
11400        cx: &mut Context<Self>,
11401    ) {
11402        if self.read_only(cx) {
11403            return;
11404        }
11405
11406        let clipboard_text = Cow::Borrowed(text);
11407
11408        self.transact(window, cx, |this, window, cx| {
11409            if let Some(mut clipboard_selections) = clipboard_selections {
11410                let old_selections = this.selections.all::<usize>(cx);
11411                let all_selections_were_entire_line =
11412                    clipboard_selections.iter().all(|s| s.is_entire_line);
11413                let first_selection_indent_column =
11414                    clipboard_selections.first().map(|s| s.first_line_indent);
11415                if clipboard_selections.len() != old_selections.len() {
11416                    clipboard_selections.drain(..);
11417                }
11418                let cursor_offset = this.selections.last::<usize>(cx).head();
11419                let mut auto_indent_on_paste = true;
11420
11421                this.buffer.update(cx, |buffer, cx| {
11422                    let snapshot = buffer.read(cx);
11423                    auto_indent_on_paste = snapshot
11424                        .language_settings_at(cursor_offset, cx)
11425                        .auto_indent_on_paste;
11426
11427                    let mut start_offset = 0;
11428                    let mut edits = Vec::new();
11429                    let mut original_indent_columns = Vec::new();
11430                    for (ix, selection) in old_selections.iter().enumerate() {
11431                        let to_insert;
11432                        let entire_line;
11433                        let original_indent_column;
11434                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11435                            let end_offset = start_offset + clipboard_selection.len;
11436                            to_insert = &clipboard_text[start_offset..end_offset];
11437                            entire_line = clipboard_selection.is_entire_line;
11438                            start_offset = end_offset + 1;
11439                            original_indent_column = Some(clipboard_selection.first_line_indent);
11440                        } else {
11441                            to_insert = clipboard_text.as_str();
11442                            entire_line = all_selections_were_entire_line;
11443                            original_indent_column = first_selection_indent_column
11444                        }
11445
11446                        // If the corresponding selection was empty when this slice of the
11447                        // clipboard text was written, then the entire line containing the
11448                        // selection was copied. If this selection is also currently empty,
11449                        // then paste the line before the current line of the buffer.
11450                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11451                            let column = selection.start.to_point(&snapshot).column as usize;
11452                            let line_start = selection.start - column;
11453                            line_start..line_start
11454                        } else {
11455                            selection.range()
11456                        };
11457
11458                        edits.push((range, to_insert));
11459                        original_indent_columns.push(original_indent_column);
11460                    }
11461                    drop(snapshot);
11462
11463                    buffer.edit(
11464                        edits,
11465                        if auto_indent_on_paste {
11466                            Some(AutoindentMode::Block {
11467                                original_indent_columns,
11468                            })
11469                        } else {
11470                            None
11471                        },
11472                        cx,
11473                    );
11474                });
11475
11476                let selections = this.selections.all::<usize>(cx);
11477                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11478                    s.select(selections)
11479                });
11480            } else {
11481                this.insert(&clipboard_text, window, cx);
11482            }
11483        });
11484    }
11485
11486    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11487        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11488        if let Some(item) = cx.read_from_clipboard() {
11489            let entries = item.entries();
11490
11491            match entries.first() {
11492                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11493                // of all the pasted entries.
11494                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11495                    .do_paste(
11496                        clipboard_string.text(),
11497                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11498                        true,
11499                        window,
11500                        cx,
11501                    ),
11502                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11503            }
11504        }
11505    }
11506
11507    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11508        if self.read_only(cx) {
11509            return;
11510        }
11511
11512        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11513
11514        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11515            if let Some((selections, _)) =
11516                self.selection_history.transaction(transaction_id).cloned()
11517            {
11518                self.change_selections(None, window, cx, |s| {
11519                    s.select_anchors(selections.to_vec());
11520                });
11521            } else {
11522                log::error!(
11523                    "No entry in selection_history found for undo. \
11524                     This may correspond to a bug where undo does not update the selection. \
11525                     If this is occurring, please add details to \
11526                     https://github.com/zed-industries/zed/issues/22692"
11527                );
11528            }
11529            self.request_autoscroll(Autoscroll::fit(), cx);
11530            self.unmark_text(window, cx);
11531            self.refresh_inline_completion(true, false, window, cx);
11532            cx.emit(EditorEvent::Edited { transaction_id });
11533            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11534        }
11535    }
11536
11537    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11538        if self.read_only(cx) {
11539            return;
11540        }
11541
11542        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11543
11544        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11545            if let Some((_, Some(selections))) =
11546                self.selection_history.transaction(transaction_id).cloned()
11547            {
11548                self.change_selections(None, window, cx, |s| {
11549                    s.select_anchors(selections.to_vec());
11550                });
11551            } else {
11552                log::error!(
11553                    "No entry in selection_history found for redo. \
11554                     This may correspond to a bug where undo does not update the selection. \
11555                     If this is occurring, please add details to \
11556                     https://github.com/zed-industries/zed/issues/22692"
11557                );
11558            }
11559            self.request_autoscroll(Autoscroll::fit(), cx);
11560            self.unmark_text(window, cx);
11561            self.refresh_inline_completion(true, false, window, cx);
11562            cx.emit(EditorEvent::Edited { transaction_id });
11563        }
11564    }
11565
11566    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11567        self.buffer
11568            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11569    }
11570
11571    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11572        self.buffer
11573            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11574    }
11575
11576    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11577        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11578        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11579            s.move_with(|map, selection| {
11580                let cursor = if selection.is_empty() {
11581                    movement::left(map, selection.start)
11582                } else {
11583                    selection.start
11584                };
11585                selection.collapse_to(cursor, SelectionGoal::None);
11586            });
11587        })
11588    }
11589
11590    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11591        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11592        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11593            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11594        })
11595    }
11596
11597    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11598        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11599        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11600            s.move_with(|map, selection| {
11601                let cursor = if selection.is_empty() {
11602                    movement::right(map, selection.end)
11603                } else {
11604                    selection.end
11605                };
11606                selection.collapse_to(cursor, SelectionGoal::None)
11607            });
11608        })
11609    }
11610
11611    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11612        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11613        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11614            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11615        })
11616    }
11617
11618    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11619        if self.take_rename(true, window, cx).is_some() {
11620            return;
11621        }
11622
11623        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11624            cx.propagate();
11625            return;
11626        }
11627
11628        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11629
11630        let text_layout_details = &self.text_layout_details(window);
11631        let selection_count = self.selections.count();
11632        let first_selection = self.selections.first_anchor();
11633
11634        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11635            s.move_with(|map, selection| {
11636                if !selection.is_empty() {
11637                    selection.goal = SelectionGoal::None;
11638                }
11639                let (cursor, goal) = movement::up(
11640                    map,
11641                    selection.start,
11642                    selection.goal,
11643                    false,
11644                    text_layout_details,
11645                );
11646                selection.collapse_to(cursor, goal);
11647            });
11648        });
11649
11650        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11651        {
11652            cx.propagate();
11653        }
11654    }
11655
11656    pub fn move_up_by_lines(
11657        &mut self,
11658        action: &MoveUpByLines,
11659        window: &mut Window,
11660        cx: &mut Context<Self>,
11661    ) {
11662        if self.take_rename(true, window, cx).is_some() {
11663            return;
11664        }
11665
11666        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11667            cx.propagate();
11668            return;
11669        }
11670
11671        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11672
11673        let text_layout_details = &self.text_layout_details(window);
11674
11675        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11676            s.move_with(|map, selection| {
11677                if !selection.is_empty() {
11678                    selection.goal = SelectionGoal::None;
11679                }
11680                let (cursor, goal) = movement::up_by_rows(
11681                    map,
11682                    selection.start,
11683                    action.lines,
11684                    selection.goal,
11685                    false,
11686                    text_layout_details,
11687                );
11688                selection.collapse_to(cursor, goal);
11689            });
11690        })
11691    }
11692
11693    pub fn move_down_by_lines(
11694        &mut self,
11695        action: &MoveDownByLines,
11696        window: &mut Window,
11697        cx: &mut Context<Self>,
11698    ) {
11699        if self.take_rename(true, window, cx).is_some() {
11700            return;
11701        }
11702
11703        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11704            cx.propagate();
11705            return;
11706        }
11707
11708        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11709
11710        let text_layout_details = &self.text_layout_details(window);
11711
11712        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11713            s.move_with(|map, selection| {
11714                if !selection.is_empty() {
11715                    selection.goal = SelectionGoal::None;
11716                }
11717                let (cursor, goal) = movement::down_by_rows(
11718                    map,
11719                    selection.start,
11720                    action.lines,
11721                    selection.goal,
11722                    false,
11723                    text_layout_details,
11724                );
11725                selection.collapse_to(cursor, goal);
11726            });
11727        })
11728    }
11729
11730    pub fn select_down_by_lines(
11731        &mut self,
11732        action: &SelectDownByLines,
11733        window: &mut Window,
11734        cx: &mut Context<Self>,
11735    ) {
11736        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11737        let text_layout_details = &self.text_layout_details(window);
11738        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11739            s.move_heads_with(|map, head, goal| {
11740                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11741            })
11742        })
11743    }
11744
11745    pub fn select_up_by_lines(
11746        &mut self,
11747        action: &SelectUpByLines,
11748        window: &mut Window,
11749        cx: &mut Context<Self>,
11750    ) {
11751        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11752        let text_layout_details = &self.text_layout_details(window);
11753        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11754            s.move_heads_with(|map, head, goal| {
11755                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11756            })
11757        })
11758    }
11759
11760    pub fn select_page_up(
11761        &mut self,
11762        _: &SelectPageUp,
11763        window: &mut Window,
11764        cx: &mut Context<Self>,
11765    ) {
11766        let Some(row_count) = self.visible_row_count() else {
11767            return;
11768        };
11769
11770        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11771
11772        let text_layout_details = &self.text_layout_details(window);
11773
11774        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11775            s.move_heads_with(|map, head, goal| {
11776                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11777            })
11778        })
11779    }
11780
11781    pub fn move_page_up(
11782        &mut self,
11783        action: &MovePageUp,
11784        window: &mut Window,
11785        cx: &mut Context<Self>,
11786    ) {
11787        if self.take_rename(true, window, cx).is_some() {
11788            return;
11789        }
11790
11791        if self
11792            .context_menu
11793            .borrow_mut()
11794            .as_mut()
11795            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11796            .unwrap_or(false)
11797        {
11798            return;
11799        }
11800
11801        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11802            cx.propagate();
11803            return;
11804        }
11805
11806        let Some(row_count) = self.visible_row_count() else {
11807            return;
11808        };
11809
11810        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11811
11812        let autoscroll = if action.center_cursor {
11813            Autoscroll::center()
11814        } else {
11815            Autoscroll::fit()
11816        };
11817
11818        let text_layout_details = &self.text_layout_details(window);
11819
11820        self.change_selections(Some(autoscroll), window, cx, |s| {
11821            s.move_with(|map, selection| {
11822                if !selection.is_empty() {
11823                    selection.goal = SelectionGoal::None;
11824                }
11825                let (cursor, goal) = movement::up_by_rows(
11826                    map,
11827                    selection.end,
11828                    row_count,
11829                    selection.goal,
11830                    false,
11831                    text_layout_details,
11832                );
11833                selection.collapse_to(cursor, goal);
11834            });
11835        });
11836    }
11837
11838    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11839        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11840        let text_layout_details = &self.text_layout_details(window);
11841        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11842            s.move_heads_with(|map, head, goal| {
11843                movement::up(map, head, goal, false, text_layout_details)
11844            })
11845        })
11846    }
11847
11848    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11849        self.take_rename(true, window, cx);
11850
11851        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11852            cx.propagate();
11853            return;
11854        }
11855
11856        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11857
11858        let text_layout_details = &self.text_layout_details(window);
11859        let selection_count = self.selections.count();
11860        let first_selection = self.selections.first_anchor();
11861
11862        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11863            s.move_with(|map, selection| {
11864                if !selection.is_empty() {
11865                    selection.goal = SelectionGoal::None;
11866                }
11867                let (cursor, goal) = movement::down(
11868                    map,
11869                    selection.end,
11870                    selection.goal,
11871                    false,
11872                    text_layout_details,
11873                );
11874                selection.collapse_to(cursor, goal);
11875            });
11876        });
11877
11878        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11879        {
11880            cx.propagate();
11881        }
11882    }
11883
11884    pub fn select_page_down(
11885        &mut self,
11886        _: &SelectPageDown,
11887        window: &mut Window,
11888        cx: &mut Context<Self>,
11889    ) {
11890        let Some(row_count) = self.visible_row_count() else {
11891            return;
11892        };
11893
11894        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11895
11896        let text_layout_details = &self.text_layout_details(window);
11897
11898        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11899            s.move_heads_with(|map, head, goal| {
11900                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11901            })
11902        })
11903    }
11904
11905    pub fn move_page_down(
11906        &mut self,
11907        action: &MovePageDown,
11908        window: &mut Window,
11909        cx: &mut Context<Self>,
11910    ) {
11911        if self.take_rename(true, window, cx).is_some() {
11912            return;
11913        }
11914
11915        if self
11916            .context_menu
11917            .borrow_mut()
11918            .as_mut()
11919            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11920            .unwrap_or(false)
11921        {
11922            return;
11923        }
11924
11925        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11926            cx.propagate();
11927            return;
11928        }
11929
11930        let Some(row_count) = self.visible_row_count() else {
11931            return;
11932        };
11933
11934        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11935
11936        let autoscroll = if action.center_cursor {
11937            Autoscroll::center()
11938        } else {
11939            Autoscroll::fit()
11940        };
11941
11942        let text_layout_details = &self.text_layout_details(window);
11943        self.change_selections(Some(autoscroll), window, cx, |s| {
11944            s.move_with(|map, selection| {
11945                if !selection.is_empty() {
11946                    selection.goal = SelectionGoal::None;
11947                }
11948                let (cursor, goal) = movement::down_by_rows(
11949                    map,
11950                    selection.end,
11951                    row_count,
11952                    selection.goal,
11953                    false,
11954                    text_layout_details,
11955                );
11956                selection.collapse_to(cursor, goal);
11957            });
11958        });
11959    }
11960
11961    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11962        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11963        let text_layout_details = &self.text_layout_details(window);
11964        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11965            s.move_heads_with(|map, head, goal| {
11966                movement::down(map, head, goal, false, text_layout_details)
11967            })
11968        });
11969    }
11970
11971    pub fn context_menu_first(
11972        &mut self,
11973        _: &ContextMenuFirst,
11974        window: &mut Window,
11975        cx: &mut Context<Self>,
11976    ) {
11977        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11978            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11979        }
11980    }
11981
11982    pub fn context_menu_prev(
11983        &mut self,
11984        _: &ContextMenuPrevious,
11985        window: &mut Window,
11986        cx: &mut Context<Self>,
11987    ) {
11988        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11989            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11990        }
11991    }
11992
11993    pub fn context_menu_next(
11994        &mut self,
11995        _: &ContextMenuNext,
11996        window: &mut Window,
11997        cx: &mut Context<Self>,
11998    ) {
11999        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12000            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12001        }
12002    }
12003
12004    pub fn context_menu_last(
12005        &mut self,
12006        _: &ContextMenuLast,
12007        window: &mut Window,
12008        cx: &mut Context<Self>,
12009    ) {
12010        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12011            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12012        }
12013    }
12014
12015    pub fn move_to_previous_word_start(
12016        &mut self,
12017        _: &MoveToPreviousWordStart,
12018        window: &mut Window,
12019        cx: &mut Context<Self>,
12020    ) {
12021        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12022        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12023            s.move_cursors_with(|map, head, _| {
12024                (
12025                    movement::previous_word_start(map, head),
12026                    SelectionGoal::None,
12027                )
12028            });
12029        })
12030    }
12031
12032    pub fn move_to_previous_subword_start(
12033        &mut self,
12034        _: &MoveToPreviousSubwordStart,
12035        window: &mut Window,
12036        cx: &mut Context<Self>,
12037    ) {
12038        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12039        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12040            s.move_cursors_with(|map, head, _| {
12041                (
12042                    movement::previous_subword_start(map, head),
12043                    SelectionGoal::None,
12044                )
12045            });
12046        })
12047    }
12048
12049    pub fn select_to_previous_word_start(
12050        &mut self,
12051        _: &SelectToPreviousWordStart,
12052        window: &mut Window,
12053        cx: &mut Context<Self>,
12054    ) {
12055        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12056        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12057            s.move_heads_with(|map, head, _| {
12058                (
12059                    movement::previous_word_start(map, head),
12060                    SelectionGoal::None,
12061                )
12062            });
12063        })
12064    }
12065
12066    pub fn select_to_previous_subword_start(
12067        &mut self,
12068        _: &SelectToPreviousSubwordStart,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12073        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12074            s.move_heads_with(|map, head, _| {
12075                (
12076                    movement::previous_subword_start(map, head),
12077                    SelectionGoal::None,
12078                )
12079            });
12080        })
12081    }
12082
12083    pub fn delete_to_previous_word_start(
12084        &mut self,
12085        action: &DeleteToPreviousWordStart,
12086        window: &mut Window,
12087        cx: &mut Context<Self>,
12088    ) {
12089        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12090        self.transact(window, cx, |this, window, cx| {
12091            this.select_autoclose_pair(window, cx);
12092            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12093                s.move_with(|map, selection| {
12094                    if selection.is_empty() {
12095                        let cursor = if action.ignore_newlines {
12096                            movement::previous_word_start(map, selection.head())
12097                        } else {
12098                            movement::previous_word_start_or_newline(map, selection.head())
12099                        };
12100                        selection.set_head(cursor, SelectionGoal::None);
12101                    }
12102                });
12103            });
12104            this.insert("", window, cx);
12105        });
12106    }
12107
12108    pub fn delete_to_previous_subword_start(
12109        &mut self,
12110        _: &DeleteToPreviousSubwordStart,
12111        window: &mut Window,
12112        cx: &mut Context<Self>,
12113    ) {
12114        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12115        self.transact(window, cx, |this, window, cx| {
12116            this.select_autoclose_pair(window, cx);
12117            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12118                s.move_with(|map, selection| {
12119                    if selection.is_empty() {
12120                        let cursor = movement::previous_subword_start(map, selection.head());
12121                        selection.set_head(cursor, SelectionGoal::None);
12122                    }
12123                });
12124            });
12125            this.insert("", window, cx);
12126        });
12127    }
12128
12129    pub fn move_to_next_word_end(
12130        &mut self,
12131        _: &MoveToNextWordEnd,
12132        window: &mut Window,
12133        cx: &mut Context<Self>,
12134    ) {
12135        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12136        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12137            s.move_cursors_with(|map, head, _| {
12138                (movement::next_word_end(map, head), SelectionGoal::None)
12139            });
12140        })
12141    }
12142
12143    pub fn move_to_next_subword_end(
12144        &mut self,
12145        _: &MoveToNextSubwordEnd,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12150        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12151            s.move_cursors_with(|map, head, _| {
12152                (movement::next_subword_end(map, head), SelectionGoal::None)
12153            });
12154        })
12155    }
12156
12157    pub fn select_to_next_word_end(
12158        &mut self,
12159        _: &SelectToNextWordEnd,
12160        window: &mut Window,
12161        cx: &mut Context<Self>,
12162    ) {
12163        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12164        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12165            s.move_heads_with(|map, head, _| {
12166                (movement::next_word_end(map, head), SelectionGoal::None)
12167            });
12168        })
12169    }
12170
12171    pub fn select_to_next_subword_end(
12172        &mut self,
12173        _: &SelectToNextSubwordEnd,
12174        window: &mut Window,
12175        cx: &mut Context<Self>,
12176    ) {
12177        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12178        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12179            s.move_heads_with(|map, head, _| {
12180                (movement::next_subword_end(map, head), SelectionGoal::None)
12181            });
12182        })
12183    }
12184
12185    pub fn delete_to_next_word_end(
12186        &mut self,
12187        action: &DeleteToNextWordEnd,
12188        window: &mut Window,
12189        cx: &mut Context<Self>,
12190    ) {
12191        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12192        self.transact(window, cx, |this, window, cx| {
12193            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12194                s.move_with(|map, selection| {
12195                    if selection.is_empty() {
12196                        let cursor = if action.ignore_newlines {
12197                            movement::next_word_end(map, selection.head())
12198                        } else {
12199                            movement::next_word_end_or_newline(map, selection.head())
12200                        };
12201                        selection.set_head(cursor, SelectionGoal::None);
12202                    }
12203                });
12204            });
12205            this.insert("", window, cx);
12206        });
12207    }
12208
12209    pub fn delete_to_next_subword_end(
12210        &mut self,
12211        _: &DeleteToNextSubwordEnd,
12212        window: &mut Window,
12213        cx: &mut Context<Self>,
12214    ) {
12215        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12216        self.transact(window, cx, |this, window, cx| {
12217            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12218                s.move_with(|map, selection| {
12219                    if selection.is_empty() {
12220                        let cursor = movement::next_subword_end(map, selection.head());
12221                        selection.set_head(cursor, SelectionGoal::None);
12222                    }
12223                });
12224            });
12225            this.insert("", window, cx);
12226        });
12227    }
12228
12229    pub fn move_to_beginning_of_line(
12230        &mut self,
12231        action: &MoveToBeginningOfLine,
12232        window: &mut Window,
12233        cx: &mut Context<Self>,
12234    ) {
12235        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12236        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12237            s.move_cursors_with(|map, head, _| {
12238                (
12239                    movement::indented_line_beginning(
12240                        map,
12241                        head,
12242                        action.stop_at_soft_wraps,
12243                        action.stop_at_indent,
12244                    ),
12245                    SelectionGoal::None,
12246                )
12247            });
12248        })
12249    }
12250
12251    pub fn select_to_beginning_of_line(
12252        &mut self,
12253        action: &SelectToBeginningOfLine,
12254        window: &mut Window,
12255        cx: &mut Context<Self>,
12256    ) {
12257        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12258        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12259            s.move_heads_with(|map, head, _| {
12260                (
12261                    movement::indented_line_beginning(
12262                        map,
12263                        head,
12264                        action.stop_at_soft_wraps,
12265                        action.stop_at_indent,
12266                    ),
12267                    SelectionGoal::None,
12268                )
12269            });
12270        });
12271    }
12272
12273    pub fn delete_to_beginning_of_line(
12274        &mut self,
12275        action: &DeleteToBeginningOfLine,
12276        window: &mut Window,
12277        cx: &mut Context<Self>,
12278    ) {
12279        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12280        self.transact(window, cx, |this, window, cx| {
12281            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12282                s.move_with(|_, selection| {
12283                    selection.reversed = true;
12284                });
12285            });
12286
12287            this.select_to_beginning_of_line(
12288                &SelectToBeginningOfLine {
12289                    stop_at_soft_wraps: false,
12290                    stop_at_indent: action.stop_at_indent,
12291                },
12292                window,
12293                cx,
12294            );
12295            this.backspace(&Backspace, window, cx);
12296        });
12297    }
12298
12299    pub fn move_to_end_of_line(
12300        &mut self,
12301        action: &MoveToEndOfLine,
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_cursors_with(|map, head, _| {
12308                (
12309                    movement::line_end(map, head, action.stop_at_soft_wraps),
12310                    SelectionGoal::None,
12311                )
12312            });
12313        })
12314    }
12315
12316    pub fn select_to_end_of_line(
12317        &mut self,
12318        action: &SelectToEndOfLine,
12319        window: &mut Window,
12320        cx: &mut Context<Self>,
12321    ) {
12322        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12323        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12324            s.move_heads_with(|map, head, _| {
12325                (
12326                    movement::line_end(map, head, action.stop_at_soft_wraps),
12327                    SelectionGoal::None,
12328                )
12329            });
12330        })
12331    }
12332
12333    pub fn delete_to_end_of_line(
12334        &mut self,
12335        _: &DeleteToEndOfLine,
12336        window: &mut Window,
12337        cx: &mut Context<Self>,
12338    ) {
12339        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12340        self.transact(window, cx, |this, window, cx| {
12341            this.select_to_end_of_line(
12342                &SelectToEndOfLine {
12343                    stop_at_soft_wraps: false,
12344                },
12345                window,
12346                cx,
12347            );
12348            this.delete(&Delete, window, cx);
12349        });
12350    }
12351
12352    pub fn cut_to_end_of_line(
12353        &mut self,
12354        _: &CutToEndOfLine,
12355        window: &mut Window,
12356        cx: &mut Context<Self>,
12357    ) {
12358        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12359        self.transact(window, cx, |this, window, cx| {
12360            this.select_to_end_of_line(
12361                &SelectToEndOfLine {
12362                    stop_at_soft_wraps: false,
12363                },
12364                window,
12365                cx,
12366            );
12367            this.cut(&Cut, window, cx);
12368        });
12369    }
12370
12371    pub fn move_to_start_of_paragraph(
12372        &mut self,
12373        _: &MoveToStartOfParagraph,
12374        window: &mut Window,
12375        cx: &mut Context<Self>,
12376    ) {
12377        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12378            cx.propagate();
12379            return;
12380        }
12381        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12382        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12383            s.move_with(|map, selection| {
12384                selection.collapse_to(
12385                    movement::start_of_paragraph(map, selection.head(), 1),
12386                    SelectionGoal::None,
12387                )
12388            });
12389        })
12390    }
12391
12392    pub fn move_to_end_of_paragraph(
12393        &mut self,
12394        _: &MoveToEndOfParagraph,
12395        window: &mut Window,
12396        cx: &mut Context<Self>,
12397    ) {
12398        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12399            cx.propagate();
12400            return;
12401        }
12402        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12403        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12404            s.move_with(|map, selection| {
12405                selection.collapse_to(
12406                    movement::end_of_paragraph(map, selection.head(), 1),
12407                    SelectionGoal::None,
12408                )
12409            });
12410        })
12411    }
12412
12413    pub fn select_to_start_of_paragraph(
12414        &mut self,
12415        _: &SelectToStartOfParagraph,
12416        window: &mut Window,
12417        cx: &mut Context<Self>,
12418    ) {
12419        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12420            cx.propagate();
12421            return;
12422        }
12423        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12424        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12425            s.move_heads_with(|map, head, _| {
12426                (
12427                    movement::start_of_paragraph(map, head, 1),
12428                    SelectionGoal::None,
12429                )
12430            });
12431        })
12432    }
12433
12434    pub fn select_to_end_of_paragraph(
12435        &mut self,
12436        _: &SelectToEndOfParagraph,
12437        window: &mut Window,
12438        cx: &mut Context<Self>,
12439    ) {
12440        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12441            cx.propagate();
12442            return;
12443        }
12444        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12445        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12446            s.move_heads_with(|map, head, _| {
12447                (
12448                    movement::end_of_paragraph(map, head, 1),
12449                    SelectionGoal::None,
12450                )
12451            });
12452        })
12453    }
12454
12455    pub fn move_to_start_of_excerpt(
12456        &mut self,
12457        _: &MoveToStartOfExcerpt,
12458        window: &mut Window,
12459        cx: &mut Context<Self>,
12460    ) {
12461        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12462            cx.propagate();
12463            return;
12464        }
12465        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12466        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12467            s.move_with(|map, selection| {
12468                selection.collapse_to(
12469                    movement::start_of_excerpt(
12470                        map,
12471                        selection.head(),
12472                        workspace::searchable::Direction::Prev,
12473                    ),
12474                    SelectionGoal::None,
12475                )
12476            });
12477        })
12478    }
12479
12480    pub fn move_to_start_of_next_excerpt(
12481        &mut self,
12482        _: &MoveToStartOfNextExcerpt,
12483        window: &mut Window,
12484        cx: &mut Context<Self>,
12485    ) {
12486        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12487            cx.propagate();
12488            return;
12489        }
12490
12491        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12492            s.move_with(|map, selection| {
12493                selection.collapse_to(
12494                    movement::start_of_excerpt(
12495                        map,
12496                        selection.head(),
12497                        workspace::searchable::Direction::Next,
12498                    ),
12499                    SelectionGoal::None,
12500                )
12501            });
12502        })
12503    }
12504
12505    pub fn move_to_end_of_excerpt(
12506        &mut self,
12507        _: &MoveToEndOfExcerpt,
12508        window: &mut Window,
12509        cx: &mut Context<Self>,
12510    ) {
12511        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12512            cx.propagate();
12513            return;
12514        }
12515        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12516        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12517            s.move_with(|map, selection| {
12518                selection.collapse_to(
12519                    movement::end_of_excerpt(
12520                        map,
12521                        selection.head(),
12522                        workspace::searchable::Direction::Next,
12523                    ),
12524                    SelectionGoal::None,
12525                )
12526            });
12527        })
12528    }
12529
12530    pub fn move_to_end_of_previous_excerpt(
12531        &mut self,
12532        _: &MoveToEndOfPreviousExcerpt,
12533        window: &mut Window,
12534        cx: &mut Context<Self>,
12535    ) {
12536        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12537            cx.propagate();
12538            return;
12539        }
12540        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12541        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12542            s.move_with(|map, selection| {
12543                selection.collapse_to(
12544                    movement::end_of_excerpt(
12545                        map,
12546                        selection.head(),
12547                        workspace::searchable::Direction::Prev,
12548                    ),
12549                    SelectionGoal::None,
12550                )
12551            });
12552        })
12553    }
12554
12555    pub fn select_to_start_of_excerpt(
12556        &mut self,
12557        _: &SelectToStartOfExcerpt,
12558        window: &mut Window,
12559        cx: &mut Context<Self>,
12560    ) {
12561        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12562            cx.propagate();
12563            return;
12564        }
12565        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12566        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12567            s.move_heads_with(|map, head, _| {
12568                (
12569                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12570                    SelectionGoal::None,
12571                )
12572            });
12573        })
12574    }
12575
12576    pub fn select_to_start_of_next_excerpt(
12577        &mut self,
12578        _: &SelectToStartOfNextExcerpt,
12579        window: &mut Window,
12580        cx: &mut Context<Self>,
12581    ) {
12582        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12583            cx.propagate();
12584            return;
12585        }
12586        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12587        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12588            s.move_heads_with(|map, head, _| {
12589                (
12590                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12591                    SelectionGoal::None,
12592                )
12593            });
12594        })
12595    }
12596
12597    pub fn select_to_end_of_excerpt(
12598        &mut self,
12599        _: &SelectToEndOfExcerpt,
12600        window: &mut Window,
12601        cx: &mut Context<Self>,
12602    ) {
12603        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12604            cx.propagate();
12605            return;
12606        }
12607        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12608        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12609            s.move_heads_with(|map, head, _| {
12610                (
12611                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12612                    SelectionGoal::None,
12613                )
12614            });
12615        })
12616    }
12617
12618    pub fn select_to_end_of_previous_excerpt(
12619        &mut self,
12620        _: &SelectToEndOfPreviousExcerpt,
12621        window: &mut Window,
12622        cx: &mut Context<Self>,
12623    ) {
12624        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12625            cx.propagate();
12626            return;
12627        }
12628        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12629        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12630            s.move_heads_with(|map, head, _| {
12631                (
12632                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12633                    SelectionGoal::None,
12634                )
12635            });
12636        })
12637    }
12638
12639    pub fn move_to_beginning(
12640        &mut self,
12641        _: &MoveToBeginning,
12642        window: &mut Window,
12643        cx: &mut Context<Self>,
12644    ) {
12645        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12646            cx.propagate();
12647            return;
12648        }
12649        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12650        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12651            s.select_ranges(vec![0..0]);
12652        });
12653    }
12654
12655    pub fn select_to_beginning(
12656        &mut self,
12657        _: &SelectToBeginning,
12658        window: &mut Window,
12659        cx: &mut Context<Self>,
12660    ) {
12661        let mut selection = self.selections.last::<Point>(cx);
12662        selection.set_head(Point::zero(), SelectionGoal::None);
12663        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12664        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12665            s.select(vec![selection]);
12666        });
12667    }
12668
12669    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12670        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12671            cx.propagate();
12672            return;
12673        }
12674        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12675        let cursor = self.buffer.read(cx).read(cx).len();
12676        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12677            s.select_ranges(vec![cursor..cursor])
12678        });
12679    }
12680
12681    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12682        self.nav_history = nav_history;
12683    }
12684
12685    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12686        self.nav_history.as_ref()
12687    }
12688
12689    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12690        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12691    }
12692
12693    fn push_to_nav_history(
12694        &mut self,
12695        cursor_anchor: Anchor,
12696        new_position: Option<Point>,
12697        is_deactivate: bool,
12698        cx: &mut Context<Self>,
12699    ) {
12700        if let Some(nav_history) = self.nav_history.as_mut() {
12701            let buffer = self.buffer.read(cx).read(cx);
12702            let cursor_position = cursor_anchor.to_point(&buffer);
12703            let scroll_state = self.scroll_manager.anchor();
12704            let scroll_top_row = scroll_state.top_row(&buffer);
12705            drop(buffer);
12706
12707            if let Some(new_position) = new_position {
12708                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12709                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12710                    return;
12711                }
12712            }
12713
12714            nav_history.push(
12715                Some(NavigationData {
12716                    cursor_anchor,
12717                    cursor_position,
12718                    scroll_anchor: scroll_state,
12719                    scroll_top_row,
12720                }),
12721                cx,
12722            );
12723            cx.emit(EditorEvent::PushedToNavHistory {
12724                anchor: cursor_anchor,
12725                is_deactivate,
12726            })
12727        }
12728    }
12729
12730    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12731        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12732        let buffer = self.buffer.read(cx).snapshot(cx);
12733        let mut selection = self.selections.first::<usize>(cx);
12734        selection.set_head(buffer.len(), SelectionGoal::None);
12735        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12736            s.select(vec![selection]);
12737        });
12738    }
12739
12740    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12741        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12742        let end = self.buffer.read(cx).read(cx).len();
12743        self.change_selections(None, window, cx, |s| {
12744            s.select_ranges(vec![0..end]);
12745        });
12746    }
12747
12748    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12749        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12751        let mut selections = self.selections.all::<Point>(cx);
12752        let max_point = display_map.buffer_snapshot.max_point();
12753        for selection in &mut selections {
12754            let rows = selection.spanned_rows(true, &display_map);
12755            selection.start = Point::new(rows.start.0, 0);
12756            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12757            selection.reversed = false;
12758        }
12759        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12760            s.select(selections);
12761        });
12762    }
12763
12764    pub fn split_selection_into_lines(
12765        &mut self,
12766        _: &SplitSelectionIntoLines,
12767        window: &mut Window,
12768        cx: &mut Context<Self>,
12769    ) {
12770        let selections = self
12771            .selections
12772            .all::<Point>(cx)
12773            .into_iter()
12774            .map(|selection| selection.start..selection.end)
12775            .collect::<Vec<_>>();
12776        self.unfold_ranges(&selections, true, true, cx);
12777
12778        let mut new_selection_ranges = Vec::new();
12779        {
12780            let buffer = self.buffer.read(cx).read(cx);
12781            for selection in selections {
12782                for row in selection.start.row..selection.end.row {
12783                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12784                    new_selection_ranges.push(cursor..cursor);
12785                }
12786
12787                let is_multiline_selection = selection.start.row != selection.end.row;
12788                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12789                // so this action feels more ergonomic when paired with other selection operations
12790                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12791                if !should_skip_last {
12792                    new_selection_ranges.push(selection.end..selection.end);
12793                }
12794            }
12795        }
12796        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12797            s.select_ranges(new_selection_ranges);
12798        });
12799    }
12800
12801    pub fn add_selection_above(
12802        &mut self,
12803        _: &AddSelectionAbove,
12804        window: &mut Window,
12805        cx: &mut Context<Self>,
12806    ) {
12807        self.add_selection(true, window, cx);
12808    }
12809
12810    pub fn add_selection_below(
12811        &mut self,
12812        _: &AddSelectionBelow,
12813        window: &mut Window,
12814        cx: &mut Context<Self>,
12815    ) {
12816        self.add_selection(false, window, cx);
12817    }
12818
12819    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12820        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12821
12822        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12823        let all_selections = self.selections.all::<Point>(cx);
12824        let text_layout_details = self.text_layout_details(window);
12825
12826        let (mut columnar_selections, new_selections_to_columnarize) = {
12827            if let Some(state) = self.add_selections_state.as_ref() {
12828                let columnar_selection_ids: HashSet<_> = state
12829                    .groups
12830                    .iter()
12831                    .flat_map(|group| group.stack.iter())
12832                    .copied()
12833                    .collect();
12834
12835                all_selections
12836                    .into_iter()
12837                    .partition(|s| columnar_selection_ids.contains(&s.id))
12838            } else {
12839                (Vec::new(), all_selections)
12840            }
12841        };
12842
12843        let mut state = self
12844            .add_selections_state
12845            .take()
12846            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12847
12848        for selection in new_selections_to_columnarize {
12849            let range = selection.display_range(&display_map).sorted();
12850            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12851            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12852            let positions = start_x.min(end_x)..start_x.max(end_x);
12853            let mut stack = Vec::new();
12854            for row in range.start.row().0..=range.end.row().0 {
12855                if let Some(selection) = self.selections.build_columnar_selection(
12856                    &display_map,
12857                    DisplayRow(row),
12858                    &positions,
12859                    selection.reversed,
12860                    &text_layout_details,
12861                ) {
12862                    stack.push(selection.id);
12863                    columnar_selections.push(selection);
12864                }
12865            }
12866            if !stack.is_empty() {
12867                if above {
12868                    stack.reverse();
12869                }
12870                state.groups.push(AddSelectionsGroup { above, stack });
12871            }
12872        }
12873
12874        let mut final_selections = Vec::new();
12875        let end_row = if above {
12876            DisplayRow(0)
12877        } else {
12878            display_map.max_point().row()
12879        };
12880
12881        let mut last_added_item_per_group = HashMap::default();
12882        for group in state.groups.iter_mut() {
12883            if let Some(last_id) = group.stack.last() {
12884                last_added_item_per_group.insert(*last_id, group);
12885            }
12886        }
12887
12888        for selection in columnar_selections {
12889            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12890                if above == group.above {
12891                    let range = selection.display_range(&display_map).sorted();
12892                    debug_assert_eq!(range.start.row(), range.end.row());
12893                    let mut row = range.start.row();
12894                    let positions =
12895                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12896                            px(start)..px(end)
12897                        } else {
12898                            let start_x =
12899                                display_map.x_for_display_point(range.start, &text_layout_details);
12900                            let end_x =
12901                                display_map.x_for_display_point(range.end, &text_layout_details);
12902                            start_x.min(end_x)..start_x.max(end_x)
12903                        };
12904
12905                    let mut maybe_new_selection = None;
12906                    while row != end_row {
12907                        if above {
12908                            row.0 -= 1;
12909                        } else {
12910                            row.0 += 1;
12911                        }
12912                        if let Some(new_selection) = self.selections.build_columnar_selection(
12913                            &display_map,
12914                            row,
12915                            &positions,
12916                            selection.reversed,
12917                            &text_layout_details,
12918                        ) {
12919                            maybe_new_selection = Some(new_selection);
12920                            break;
12921                        }
12922                    }
12923
12924                    if let Some(new_selection) = maybe_new_selection {
12925                        group.stack.push(new_selection.id);
12926                        if above {
12927                            final_selections.push(new_selection);
12928                            final_selections.push(selection);
12929                        } else {
12930                            final_selections.push(selection);
12931                            final_selections.push(new_selection);
12932                        }
12933                    } else {
12934                        final_selections.push(selection);
12935                    }
12936                } else {
12937                    group.stack.pop();
12938                }
12939            } else {
12940                final_selections.push(selection);
12941            }
12942        }
12943
12944        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12945            s.select(final_selections);
12946        });
12947
12948        let final_selection_ids: HashSet<_> = self
12949            .selections
12950            .all::<Point>(cx)
12951            .iter()
12952            .map(|s| s.id)
12953            .collect();
12954        state.groups.retain_mut(|group| {
12955            // selections might get merged above so we remove invalid items from stacks
12956            group.stack.retain(|id| final_selection_ids.contains(id));
12957
12958            // single selection in stack can be treated as initial state
12959            group.stack.len() > 1
12960        });
12961
12962        if !state.groups.is_empty() {
12963            self.add_selections_state = Some(state);
12964        }
12965    }
12966
12967    fn select_match_ranges(
12968        &mut self,
12969        range: Range<usize>,
12970        reversed: bool,
12971        replace_newest: bool,
12972        auto_scroll: Option<Autoscroll>,
12973        window: &mut Window,
12974        cx: &mut Context<Editor>,
12975    ) {
12976        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12977        self.change_selections(auto_scroll, window, cx, |s| {
12978            if replace_newest {
12979                s.delete(s.newest_anchor().id);
12980            }
12981            if reversed {
12982                s.insert_range(range.end..range.start);
12983            } else {
12984                s.insert_range(range);
12985            }
12986        });
12987    }
12988
12989    pub fn select_next_match_internal(
12990        &mut self,
12991        display_map: &DisplaySnapshot,
12992        replace_newest: bool,
12993        autoscroll: Option<Autoscroll>,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) -> Result<()> {
12997        let buffer = &display_map.buffer_snapshot;
12998        let mut selections = self.selections.all::<usize>(cx);
12999        if let Some(mut select_next_state) = self.select_next_state.take() {
13000            let query = &select_next_state.query;
13001            if !select_next_state.done {
13002                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13003                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13004                let mut next_selected_range = None;
13005
13006                let bytes_after_last_selection =
13007                    buffer.bytes_in_range(last_selection.end..buffer.len());
13008                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13009                let query_matches = query
13010                    .stream_find_iter(bytes_after_last_selection)
13011                    .map(|result| (last_selection.end, result))
13012                    .chain(
13013                        query
13014                            .stream_find_iter(bytes_before_first_selection)
13015                            .map(|result| (0, result)),
13016                    );
13017
13018                for (start_offset, query_match) in query_matches {
13019                    let query_match = query_match.unwrap(); // can only fail due to I/O
13020                    let offset_range =
13021                        start_offset + query_match.start()..start_offset + query_match.end();
13022                    let display_range = offset_range.start.to_display_point(display_map)
13023                        ..offset_range.end.to_display_point(display_map);
13024
13025                    if !select_next_state.wordwise
13026                        || (!movement::is_inside_word(display_map, display_range.start)
13027                            && !movement::is_inside_word(display_map, display_range.end))
13028                    {
13029                        // TODO: This is n^2, because we might check all the selections
13030                        if !selections
13031                            .iter()
13032                            .any(|selection| selection.range().overlaps(&offset_range))
13033                        {
13034                            next_selected_range = Some(offset_range);
13035                            break;
13036                        }
13037                    }
13038                }
13039
13040                if let Some(next_selected_range) = next_selected_range {
13041                    self.select_match_ranges(
13042                        next_selected_range,
13043                        last_selection.reversed,
13044                        replace_newest,
13045                        autoscroll,
13046                        window,
13047                        cx,
13048                    );
13049                } else {
13050                    select_next_state.done = true;
13051                }
13052            }
13053
13054            self.select_next_state = Some(select_next_state);
13055        } else {
13056            let mut only_carets = true;
13057            let mut same_text_selected = true;
13058            let mut selected_text = None;
13059
13060            let mut selections_iter = selections.iter().peekable();
13061            while let Some(selection) = selections_iter.next() {
13062                if selection.start != selection.end {
13063                    only_carets = false;
13064                }
13065
13066                if same_text_selected {
13067                    if selected_text.is_none() {
13068                        selected_text =
13069                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13070                    }
13071
13072                    if let Some(next_selection) = selections_iter.peek() {
13073                        if next_selection.range().len() == selection.range().len() {
13074                            let next_selected_text = buffer
13075                                .text_for_range(next_selection.range())
13076                                .collect::<String>();
13077                            if Some(next_selected_text) != selected_text {
13078                                same_text_selected = false;
13079                                selected_text = None;
13080                            }
13081                        } else {
13082                            same_text_selected = false;
13083                            selected_text = None;
13084                        }
13085                    }
13086                }
13087            }
13088
13089            if only_carets {
13090                for selection in &mut selections {
13091                    let word_range = movement::surrounding_word(
13092                        display_map,
13093                        selection.start.to_display_point(display_map),
13094                    );
13095                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13096                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13097                    selection.goal = SelectionGoal::None;
13098                    selection.reversed = false;
13099                    self.select_match_ranges(
13100                        selection.start..selection.end,
13101                        selection.reversed,
13102                        replace_newest,
13103                        autoscroll,
13104                        window,
13105                        cx,
13106                    );
13107                }
13108
13109                if selections.len() == 1 {
13110                    let selection = selections
13111                        .last()
13112                        .expect("ensured that there's only one selection");
13113                    let query = buffer
13114                        .text_for_range(selection.start..selection.end)
13115                        .collect::<String>();
13116                    let is_empty = query.is_empty();
13117                    let select_state = SelectNextState {
13118                        query: AhoCorasick::new(&[query])?,
13119                        wordwise: true,
13120                        done: is_empty,
13121                    };
13122                    self.select_next_state = Some(select_state);
13123                } else {
13124                    self.select_next_state = None;
13125                }
13126            } else if let Some(selected_text) = selected_text {
13127                self.select_next_state = Some(SelectNextState {
13128                    query: AhoCorasick::new(&[selected_text])?,
13129                    wordwise: false,
13130                    done: false,
13131                });
13132                self.select_next_match_internal(
13133                    display_map,
13134                    replace_newest,
13135                    autoscroll,
13136                    window,
13137                    cx,
13138                )?;
13139            }
13140        }
13141        Ok(())
13142    }
13143
13144    pub fn select_all_matches(
13145        &mut self,
13146        _action: &SelectAllMatches,
13147        window: &mut Window,
13148        cx: &mut Context<Self>,
13149    ) -> Result<()> {
13150        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13151
13152        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13153
13154        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13155        let Some(select_next_state) = self.select_next_state.as_mut() else {
13156            return Ok(());
13157        };
13158        if select_next_state.done {
13159            return Ok(());
13160        }
13161
13162        let mut new_selections = Vec::new();
13163
13164        let reversed = self.selections.oldest::<usize>(cx).reversed;
13165        let buffer = &display_map.buffer_snapshot;
13166        let query_matches = select_next_state
13167            .query
13168            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13169
13170        for query_match in query_matches.into_iter() {
13171            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13172            let offset_range = if reversed {
13173                query_match.end()..query_match.start()
13174            } else {
13175                query_match.start()..query_match.end()
13176            };
13177            let display_range = offset_range.start.to_display_point(&display_map)
13178                ..offset_range.end.to_display_point(&display_map);
13179
13180            if !select_next_state.wordwise
13181                || (!movement::is_inside_word(&display_map, display_range.start)
13182                    && !movement::is_inside_word(&display_map, display_range.end))
13183            {
13184                new_selections.push(offset_range.start..offset_range.end);
13185            }
13186        }
13187
13188        select_next_state.done = true;
13189        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13190        self.change_selections(None, window, cx, |selections| {
13191            selections.select_ranges(new_selections)
13192        });
13193
13194        Ok(())
13195    }
13196
13197    pub fn select_next(
13198        &mut self,
13199        action: &SelectNext,
13200        window: &mut Window,
13201        cx: &mut Context<Self>,
13202    ) -> Result<()> {
13203        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13205        self.select_next_match_internal(
13206            &display_map,
13207            action.replace_newest,
13208            Some(Autoscroll::newest()),
13209            window,
13210            cx,
13211        )?;
13212        Ok(())
13213    }
13214
13215    pub fn select_previous(
13216        &mut self,
13217        action: &SelectPrevious,
13218        window: &mut Window,
13219        cx: &mut Context<Self>,
13220    ) -> Result<()> {
13221        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13222        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13223        let buffer = &display_map.buffer_snapshot;
13224        let mut selections = self.selections.all::<usize>(cx);
13225        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13226            let query = &select_prev_state.query;
13227            if !select_prev_state.done {
13228                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13229                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13230                let mut next_selected_range = None;
13231                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13232                let bytes_before_last_selection =
13233                    buffer.reversed_bytes_in_range(0..last_selection.start);
13234                let bytes_after_first_selection =
13235                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13236                let query_matches = query
13237                    .stream_find_iter(bytes_before_last_selection)
13238                    .map(|result| (last_selection.start, result))
13239                    .chain(
13240                        query
13241                            .stream_find_iter(bytes_after_first_selection)
13242                            .map(|result| (buffer.len(), result)),
13243                    );
13244                for (end_offset, query_match) in query_matches {
13245                    let query_match = query_match.unwrap(); // can only fail due to I/O
13246                    let offset_range =
13247                        end_offset - query_match.end()..end_offset - query_match.start();
13248                    let display_range = offset_range.start.to_display_point(&display_map)
13249                        ..offset_range.end.to_display_point(&display_map);
13250
13251                    if !select_prev_state.wordwise
13252                        || (!movement::is_inside_word(&display_map, display_range.start)
13253                            && !movement::is_inside_word(&display_map, display_range.end))
13254                    {
13255                        next_selected_range = Some(offset_range);
13256                        break;
13257                    }
13258                }
13259
13260                if let Some(next_selected_range) = next_selected_range {
13261                    self.select_match_ranges(
13262                        next_selected_range,
13263                        last_selection.reversed,
13264                        action.replace_newest,
13265                        Some(Autoscroll::newest()),
13266                        window,
13267                        cx,
13268                    );
13269                } else {
13270                    select_prev_state.done = true;
13271                }
13272            }
13273
13274            self.select_prev_state = Some(select_prev_state);
13275        } else {
13276            let mut only_carets = true;
13277            let mut same_text_selected = true;
13278            let mut selected_text = None;
13279
13280            let mut selections_iter = selections.iter().peekable();
13281            while let Some(selection) = selections_iter.next() {
13282                if selection.start != selection.end {
13283                    only_carets = false;
13284                }
13285
13286                if same_text_selected {
13287                    if selected_text.is_none() {
13288                        selected_text =
13289                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13290                    }
13291
13292                    if let Some(next_selection) = selections_iter.peek() {
13293                        if next_selection.range().len() == selection.range().len() {
13294                            let next_selected_text = buffer
13295                                .text_for_range(next_selection.range())
13296                                .collect::<String>();
13297                            if Some(next_selected_text) != selected_text {
13298                                same_text_selected = false;
13299                                selected_text = None;
13300                            }
13301                        } else {
13302                            same_text_selected = false;
13303                            selected_text = None;
13304                        }
13305                    }
13306                }
13307            }
13308
13309            if only_carets {
13310                for selection in &mut selections {
13311                    let word_range = movement::surrounding_word(
13312                        &display_map,
13313                        selection.start.to_display_point(&display_map),
13314                    );
13315                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13316                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13317                    selection.goal = SelectionGoal::None;
13318                    selection.reversed = false;
13319                    self.select_match_ranges(
13320                        selection.start..selection.end,
13321                        selection.reversed,
13322                        action.replace_newest,
13323                        Some(Autoscroll::newest()),
13324                        window,
13325                        cx,
13326                    );
13327                }
13328                if selections.len() == 1 {
13329                    let selection = selections
13330                        .last()
13331                        .expect("ensured that there's only one selection");
13332                    let query = buffer
13333                        .text_for_range(selection.start..selection.end)
13334                        .collect::<String>();
13335                    let is_empty = query.is_empty();
13336                    let select_state = SelectNextState {
13337                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13338                        wordwise: true,
13339                        done: is_empty,
13340                    };
13341                    self.select_prev_state = Some(select_state);
13342                } else {
13343                    self.select_prev_state = None;
13344                }
13345            } else if let Some(selected_text) = selected_text {
13346                self.select_prev_state = Some(SelectNextState {
13347                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13348                    wordwise: false,
13349                    done: false,
13350                });
13351                self.select_previous(action, window, cx)?;
13352            }
13353        }
13354        Ok(())
13355    }
13356
13357    pub fn find_next_match(
13358        &mut self,
13359        _: &FindNextMatch,
13360        window: &mut Window,
13361        cx: &mut Context<Self>,
13362    ) -> Result<()> {
13363        let selections = self.selections.disjoint_anchors();
13364        match selections.first() {
13365            Some(first) if selections.len() >= 2 => {
13366                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13367                    s.select_ranges([first.range()]);
13368                });
13369            }
13370            _ => self.select_next(
13371                &SelectNext {
13372                    replace_newest: true,
13373                },
13374                window,
13375                cx,
13376            )?,
13377        }
13378        Ok(())
13379    }
13380
13381    pub fn find_previous_match(
13382        &mut self,
13383        _: &FindPreviousMatch,
13384        window: &mut Window,
13385        cx: &mut Context<Self>,
13386    ) -> Result<()> {
13387        let selections = self.selections.disjoint_anchors();
13388        match selections.last() {
13389            Some(last) if selections.len() >= 2 => {
13390                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13391                    s.select_ranges([last.range()]);
13392                });
13393            }
13394            _ => self.select_previous(
13395                &SelectPrevious {
13396                    replace_newest: true,
13397                },
13398                window,
13399                cx,
13400            )?,
13401        }
13402        Ok(())
13403    }
13404
13405    pub fn toggle_comments(
13406        &mut self,
13407        action: &ToggleComments,
13408        window: &mut Window,
13409        cx: &mut Context<Self>,
13410    ) {
13411        if self.read_only(cx) {
13412            return;
13413        }
13414        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13415        let text_layout_details = &self.text_layout_details(window);
13416        self.transact(window, cx, |this, window, cx| {
13417            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13418            let mut edits = Vec::new();
13419            let mut selection_edit_ranges = Vec::new();
13420            let mut last_toggled_row = None;
13421            let snapshot = this.buffer.read(cx).read(cx);
13422            let empty_str: Arc<str> = Arc::default();
13423            let mut suffixes_inserted = Vec::new();
13424            let ignore_indent = action.ignore_indent;
13425
13426            fn comment_prefix_range(
13427                snapshot: &MultiBufferSnapshot,
13428                row: MultiBufferRow,
13429                comment_prefix: &str,
13430                comment_prefix_whitespace: &str,
13431                ignore_indent: bool,
13432            ) -> Range<Point> {
13433                let indent_size = if ignore_indent {
13434                    0
13435                } else {
13436                    snapshot.indent_size_for_line(row).len
13437                };
13438
13439                let start = Point::new(row.0, indent_size);
13440
13441                let mut line_bytes = snapshot
13442                    .bytes_in_range(start..snapshot.max_point())
13443                    .flatten()
13444                    .copied();
13445
13446                // If this line currently begins with the line comment prefix, then record
13447                // the range containing the prefix.
13448                if line_bytes
13449                    .by_ref()
13450                    .take(comment_prefix.len())
13451                    .eq(comment_prefix.bytes())
13452                {
13453                    // Include any whitespace that matches the comment prefix.
13454                    let matching_whitespace_len = line_bytes
13455                        .zip(comment_prefix_whitespace.bytes())
13456                        .take_while(|(a, b)| a == b)
13457                        .count() as u32;
13458                    let end = Point::new(
13459                        start.row,
13460                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13461                    );
13462                    start..end
13463                } else {
13464                    start..start
13465                }
13466            }
13467
13468            fn comment_suffix_range(
13469                snapshot: &MultiBufferSnapshot,
13470                row: MultiBufferRow,
13471                comment_suffix: &str,
13472                comment_suffix_has_leading_space: bool,
13473            ) -> Range<Point> {
13474                let end = Point::new(row.0, snapshot.line_len(row));
13475                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13476
13477                let mut line_end_bytes = snapshot
13478                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13479                    .flatten()
13480                    .copied();
13481
13482                let leading_space_len = if suffix_start_column > 0
13483                    && line_end_bytes.next() == Some(b' ')
13484                    && comment_suffix_has_leading_space
13485                {
13486                    1
13487                } else {
13488                    0
13489                };
13490
13491                // If this line currently begins with the line comment prefix, then record
13492                // the range containing the prefix.
13493                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13494                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13495                    start..end
13496                } else {
13497                    end..end
13498                }
13499            }
13500
13501            // TODO: Handle selections that cross excerpts
13502            for selection in &mut selections {
13503                let start_column = snapshot
13504                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13505                    .len;
13506                let language = if let Some(language) =
13507                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13508                {
13509                    language
13510                } else {
13511                    continue;
13512                };
13513
13514                selection_edit_ranges.clear();
13515
13516                // If multiple selections contain a given row, avoid processing that
13517                // row more than once.
13518                let mut start_row = MultiBufferRow(selection.start.row);
13519                if last_toggled_row == Some(start_row) {
13520                    start_row = start_row.next_row();
13521                }
13522                let end_row =
13523                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13524                        MultiBufferRow(selection.end.row - 1)
13525                    } else {
13526                        MultiBufferRow(selection.end.row)
13527                    };
13528                last_toggled_row = Some(end_row);
13529
13530                if start_row > end_row {
13531                    continue;
13532                }
13533
13534                // If the language has line comments, toggle those.
13535                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13536
13537                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13538                if ignore_indent {
13539                    full_comment_prefixes = full_comment_prefixes
13540                        .into_iter()
13541                        .map(|s| Arc::from(s.trim_end()))
13542                        .collect();
13543                }
13544
13545                if !full_comment_prefixes.is_empty() {
13546                    let first_prefix = full_comment_prefixes
13547                        .first()
13548                        .expect("prefixes is non-empty");
13549                    let prefix_trimmed_lengths = full_comment_prefixes
13550                        .iter()
13551                        .map(|p| p.trim_end_matches(' ').len())
13552                        .collect::<SmallVec<[usize; 4]>>();
13553
13554                    let mut all_selection_lines_are_comments = true;
13555
13556                    for row in start_row.0..=end_row.0 {
13557                        let row = MultiBufferRow(row);
13558                        if start_row < end_row && snapshot.is_line_blank(row) {
13559                            continue;
13560                        }
13561
13562                        let prefix_range = full_comment_prefixes
13563                            .iter()
13564                            .zip(prefix_trimmed_lengths.iter().copied())
13565                            .map(|(prefix, trimmed_prefix_len)| {
13566                                comment_prefix_range(
13567                                    snapshot.deref(),
13568                                    row,
13569                                    &prefix[..trimmed_prefix_len],
13570                                    &prefix[trimmed_prefix_len..],
13571                                    ignore_indent,
13572                                )
13573                            })
13574                            .max_by_key(|range| range.end.column - range.start.column)
13575                            .expect("prefixes is non-empty");
13576
13577                        if prefix_range.is_empty() {
13578                            all_selection_lines_are_comments = false;
13579                        }
13580
13581                        selection_edit_ranges.push(prefix_range);
13582                    }
13583
13584                    if all_selection_lines_are_comments {
13585                        edits.extend(
13586                            selection_edit_ranges
13587                                .iter()
13588                                .cloned()
13589                                .map(|range| (range, empty_str.clone())),
13590                        );
13591                    } else {
13592                        let min_column = selection_edit_ranges
13593                            .iter()
13594                            .map(|range| range.start.column)
13595                            .min()
13596                            .unwrap_or(0);
13597                        edits.extend(selection_edit_ranges.iter().map(|range| {
13598                            let position = Point::new(range.start.row, min_column);
13599                            (position..position, first_prefix.clone())
13600                        }));
13601                    }
13602                } else if let Some((full_comment_prefix, comment_suffix)) =
13603                    language.block_comment_delimiters()
13604                {
13605                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13606                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13607                    let prefix_range = comment_prefix_range(
13608                        snapshot.deref(),
13609                        start_row,
13610                        comment_prefix,
13611                        comment_prefix_whitespace,
13612                        ignore_indent,
13613                    );
13614                    let suffix_range = comment_suffix_range(
13615                        snapshot.deref(),
13616                        end_row,
13617                        comment_suffix.trim_start_matches(' '),
13618                        comment_suffix.starts_with(' '),
13619                    );
13620
13621                    if prefix_range.is_empty() || suffix_range.is_empty() {
13622                        edits.push((
13623                            prefix_range.start..prefix_range.start,
13624                            full_comment_prefix.clone(),
13625                        ));
13626                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13627                        suffixes_inserted.push((end_row, comment_suffix.len()));
13628                    } else {
13629                        edits.push((prefix_range, empty_str.clone()));
13630                        edits.push((suffix_range, empty_str.clone()));
13631                    }
13632                } else {
13633                    continue;
13634                }
13635            }
13636
13637            drop(snapshot);
13638            this.buffer.update(cx, |buffer, cx| {
13639                buffer.edit(edits, None, cx);
13640            });
13641
13642            // Adjust selections so that they end before any comment suffixes that
13643            // were inserted.
13644            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13645            let mut selections = this.selections.all::<Point>(cx);
13646            let snapshot = this.buffer.read(cx).read(cx);
13647            for selection in &mut selections {
13648                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13649                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13650                        Ordering::Less => {
13651                            suffixes_inserted.next();
13652                            continue;
13653                        }
13654                        Ordering::Greater => break,
13655                        Ordering::Equal => {
13656                            if selection.end.column == snapshot.line_len(row) {
13657                                if selection.is_empty() {
13658                                    selection.start.column -= suffix_len as u32;
13659                                }
13660                                selection.end.column -= suffix_len as u32;
13661                            }
13662                            break;
13663                        }
13664                    }
13665                }
13666            }
13667
13668            drop(snapshot);
13669            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13670                s.select(selections)
13671            });
13672
13673            let selections = this.selections.all::<Point>(cx);
13674            let selections_on_single_row = selections.windows(2).all(|selections| {
13675                selections[0].start.row == selections[1].start.row
13676                    && selections[0].end.row == selections[1].end.row
13677                    && selections[0].start.row == selections[0].end.row
13678            });
13679            let selections_selecting = selections
13680                .iter()
13681                .any(|selection| selection.start != selection.end);
13682            let advance_downwards = action.advance_downwards
13683                && selections_on_single_row
13684                && !selections_selecting
13685                && !matches!(this.mode, EditorMode::SingleLine { .. });
13686
13687            if advance_downwards {
13688                let snapshot = this.buffer.read(cx).snapshot(cx);
13689
13690                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13691                    s.move_cursors_with(|display_snapshot, display_point, _| {
13692                        let mut point = display_point.to_point(display_snapshot);
13693                        point.row += 1;
13694                        point = snapshot.clip_point(point, Bias::Left);
13695                        let display_point = point.to_display_point(display_snapshot);
13696                        let goal = SelectionGoal::HorizontalPosition(
13697                            display_snapshot
13698                                .x_for_display_point(display_point, text_layout_details)
13699                                .into(),
13700                        );
13701                        (display_point, goal)
13702                    })
13703                });
13704            }
13705        });
13706    }
13707
13708    pub fn select_enclosing_symbol(
13709        &mut self,
13710        _: &SelectEnclosingSymbol,
13711        window: &mut Window,
13712        cx: &mut Context<Self>,
13713    ) {
13714        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13715
13716        let buffer = self.buffer.read(cx).snapshot(cx);
13717        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13718
13719        fn update_selection(
13720            selection: &Selection<usize>,
13721            buffer_snap: &MultiBufferSnapshot,
13722        ) -> Option<Selection<usize>> {
13723            let cursor = selection.head();
13724            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13725            for symbol in symbols.iter().rev() {
13726                let start = symbol.range.start.to_offset(buffer_snap);
13727                let end = symbol.range.end.to_offset(buffer_snap);
13728                let new_range = start..end;
13729                if start < selection.start || end > selection.end {
13730                    return Some(Selection {
13731                        id: selection.id,
13732                        start: new_range.start,
13733                        end: new_range.end,
13734                        goal: SelectionGoal::None,
13735                        reversed: selection.reversed,
13736                    });
13737                }
13738            }
13739            None
13740        }
13741
13742        let mut selected_larger_symbol = false;
13743        let new_selections = old_selections
13744            .iter()
13745            .map(|selection| match update_selection(selection, &buffer) {
13746                Some(new_selection) => {
13747                    if new_selection.range() != selection.range() {
13748                        selected_larger_symbol = true;
13749                    }
13750                    new_selection
13751                }
13752                None => selection.clone(),
13753            })
13754            .collect::<Vec<_>>();
13755
13756        if selected_larger_symbol {
13757            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13758                s.select(new_selections);
13759            });
13760        }
13761    }
13762
13763    pub fn select_larger_syntax_node(
13764        &mut self,
13765        _: &SelectLargerSyntaxNode,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        let Some(visible_row_count) = self.visible_row_count() else {
13770            return;
13771        };
13772        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13773        if old_selections.is_empty() {
13774            return;
13775        }
13776
13777        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13778
13779        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13780        let buffer = self.buffer.read(cx).snapshot(cx);
13781
13782        let mut selected_larger_node = false;
13783        let mut new_selections = old_selections
13784            .iter()
13785            .map(|selection| {
13786                let old_range = selection.start..selection.end;
13787
13788                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13789                    // manually select word at selection
13790                    if ["string_content", "inline"].contains(&node.kind()) {
13791                        let word_range = {
13792                            let display_point = buffer
13793                                .offset_to_point(old_range.start)
13794                                .to_display_point(&display_map);
13795                            let Range { start, end } =
13796                                movement::surrounding_word(&display_map, display_point);
13797                            start.to_point(&display_map).to_offset(&buffer)
13798                                ..end.to_point(&display_map).to_offset(&buffer)
13799                        };
13800                        // ignore if word is already selected
13801                        if !word_range.is_empty() && old_range != word_range {
13802                            let last_word_range = {
13803                                let display_point = buffer
13804                                    .offset_to_point(old_range.end)
13805                                    .to_display_point(&display_map);
13806                                let Range { start, end } =
13807                                    movement::surrounding_word(&display_map, display_point);
13808                                start.to_point(&display_map).to_offset(&buffer)
13809                                    ..end.to_point(&display_map).to_offset(&buffer)
13810                            };
13811                            // only select word if start and end point belongs to same word
13812                            if word_range == last_word_range {
13813                                selected_larger_node = true;
13814                                return Selection {
13815                                    id: selection.id,
13816                                    start: word_range.start,
13817                                    end: word_range.end,
13818                                    goal: SelectionGoal::None,
13819                                    reversed: selection.reversed,
13820                                };
13821                            }
13822                        }
13823                    }
13824                }
13825
13826                let mut new_range = old_range.clone();
13827                while let Some((_node, containing_range)) =
13828                    buffer.syntax_ancestor(new_range.clone())
13829                {
13830                    new_range = match containing_range {
13831                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13832                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13833                    };
13834                    if !display_map.intersects_fold(new_range.start)
13835                        && !display_map.intersects_fold(new_range.end)
13836                    {
13837                        break;
13838                    }
13839                }
13840
13841                selected_larger_node |= new_range != old_range;
13842                Selection {
13843                    id: selection.id,
13844                    start: new_range.start,
13845                    end: new_range.end,
13846                    goal: SelectionGoal::None,
13847                    reversed: selection.reversed,
13848                }
13849            })
13850            .collect::<Vec<_>>();
13851
13852        if !selected_larger_node {
13853            return; // don't put this call in the history
13854        }
13855
13856        // scroll based on transformation done to the last selection created by the user
13857        let (last_old, last_new) = old_selections
13858            .last()
13859            .zip(new_selections.last().cloned())
13860            .expect("old_selections isn't empty");
13861
13862        // revert selection
13863        let is_selection_reversed = {
13864            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13865            new_selections.last_mut().expect("checked above").reversed =
13866                should_newest_selection_be_reversed;
13867            should_newest_selection_be_reversed
13868        };
13869
13870        if selected_larger_node {
13871            self.select_syntax_node_history.disable_clearing = true;
13872            self.change_selections(None, window, cx, |s| {
13873                s.select(new_selections.clone());
13874            });
13875            self.select_syntax_node_history.disable_clearing = false;
13876        }
13877
13878        let start_row = last_new.start.to_display_point(&display_map).row().0;
13879        let end_row = last_new.end.to_display_point(&display_map).row().0;
13880        let selection_height = end_row - start_row + 1;
13881        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13882
13883        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13884        let scroll_behavior = if fits_on_the_screen {
13885            self.request_autoscroll(Autoscroll::fit(), cx);
13886            SelectSyntaxNodeScrollBehavior::FitSelection
13887        } else if is_selection_reversed {
13888            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13889            SelectSyntaxNodeScrollBehavior::CursorTop
13890        } else {
13891            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13892            SelectSyntaxNodeScrollBehavior::CursorBottom
13893        };
13894
13895        self.select_syntax_node_history.push((
13896            old_selections,
13897            scroll_behavior,
13898            is_selection_reversed,
13899        ));
13900    }
13901
13902    pub fn select_smaller_syntax_node(
13903        &mut self,
13904        _: &SelectSmallerSyntaxNode,
13905        window: &mut Window,
13906        cx: &mut Context<Self>,
13907    ) {
13908        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13909
13910        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13911            self.select_syntax_node_history.pop()
13912        {
13913            if let Some(selection) = selections.last_mut() {
13914                selection.reversed = is_selection_reversed;
13915            }
13916
13917            self.select_syntax_node_history.disable_clearing = true;
13918            self.change_selections(None, window, cx, |s| {
13919                s.select(selections.to_vec());
13920            });
13921            self.select_syntax_node_history.disable_clearing = false;
13922
13923            match scroll_behavior {
13924                SelectSyntaxNodeScrollBehavior::CursorTop => {
13925                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13926                }
13927                SelectSyntaxNodeScrollBehavior::FitSelection => {
13928                    self.request_autoscroll(Autoscroll::fit(), cx);
13929                }
13930                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13931                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13932                }
13933            }
13934        }
13935    }
13936
13937    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13938        if !EditorSettings::get_global(cx).gutter.runnables {
13939            self.clear_tasks();
13940            return Task::ready(());
13941        }
13942        let project = self.project.as_ref().map(Entity::downgrade);
13943        let task_sources = self.lsp_task_sources(cx);
13944        let multi_buffer = self.buffer.downgrade();
13945        cx.spawn_in(window, async move |editor, cx| {
13946            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13947            let Some(project) = project.and_then(|p| p.upgrade()) else {
13948                return;
13949            };
13950            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13951                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13952            }) else {
13953                return;
13954            };
13955
13956            let hide_runnables = project
13957                .update(cx, |project, cx| {
13958                    // Do not display any test indicators in non-dev server remote projects.
13959                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13960                })
13961                .unwrap_or(true);
13962            if hide_runnables {
13963                return;
13964            }
13965            let new_rows =
13966                cx.background_spawn({
13967                    let snapshot = display_snapshot.clone();
13968                    async move {
13969                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13970                    }
13971                })
13972                    .await;
13973            let Ok(lsp_tasks) =
13974                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13975            else {
13976                return;
13977            };
13978            let lsp_tasks = lsp_tasks.await;
13979
13980            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13981                lsp_tasks
13982                    .into_iter()
13983                    .flat_map(|(kind, tasks)| {
13984                        tasks.into_iter().filter_map(move |(location, task)| {
13985                            Some((kind.clone(), location?, task))
13986                        })
13987                    })
13988                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13989                        let buffer = location.target.buffer;
13990                        let buffer_snapshot = buffer.read(cx).snapshot();
13991                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13992                            |(excerpt_id, snapshot, _)| {
13993                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13994                                    display_snapshot
13995                                        .buffer_snapshot
13996                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13997                                } else {
13998                                    None
13999                                }
14000                            },
14001                        );
14002                        if let Some(offset) = offset {
14003                            let task_buffer_range =
14004                                location.target.range.to_point(&buffer_snapshot);
14005                            let context_buffer_range =
14006                                task_buffer_range.to_offset(&buffer_snapshot);
14007                            let context_range = BufferOffset(context_buffer_range.start)
14008                                ..BufferOffset(context_buffer_range.end);
14009
14010                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14011                                .or_insert_with(|| RunnableTasks {
14012                                    templates: Vec::new(),
14013                                    offset,
14014                                    column: task_buffer_range.start.column,
14015                                    extra_variables: HashMap::default(),
14016                                    context_range,
14017                                })
14018                                .templates
14019                                .push((kind, task.original_task().clone()));
14020                        }
14021
14022                        acc
14023                    })
14024            }) else {
14025                return;
14026            };
14027
14028            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14029                buffer.language_settings(cx).tasks.prefer_lsp
14030            }) else {
14031                return;
14032            };
14033
14034            let rows = Self::runnable_rows(
14035                project,
14036                display_snapshot,
14037                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14038                new_rows,
14039                cx.clone(),
14040            )
14041            .await;
14042            editor
14043                .update(cx, |editor, _| {
14044                    editor.clear_tasks();
14045                    for (key, mut value) in rows {
14046                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14047                            value.templates.extend(lsp_tasks.templates);
14048                        }
14049
14050                        editor.insert_tasks(key, value);
14051                    }
14052                    for (key, value) in lsp_tasks_by_rows {
14053                        editor.insert_tasks(key, value);
14054                    }
14055                })
14056                .ok();
14057        })
14058    }
14059    fn fetch_runnable_ranges(
14060        snapshot: &DisplaySnapshot,
14061        range: Range<Anchor>,
14062    ) -> Vec<language::RunnableRange> {
14063        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14064    }
14065
14066    fn runnable_rows(
14067        project: Entity<Project>,
14068        snapshot: DisplaySnapshot,
14069        prefer_lsp: bool,
14070        runnable_ranges: Vec<RunnableRange>,
14071        cx: AsyncWindowContext,
14072    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14073        cx.spawn(async move |cx| {
14074            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14075            for mut runnable in runnable_ranges {
14076                let Some(tasks) = cx
14077                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14078                    .ok()
14079                else {
14080                    continue;
14081                };
14082                let mut tasks = tasks.await;
14083
14084                if prefer_lsp {
14085                    tasks.retain(|(task_kind, _)| {
14086                        !matches!(task_kind, TaskSourceKind::Language { .. })
14087                    });
14088                }
14089                if tasks.is_empty() {
14090                    continue;
14091                }
14092
14093                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14094                let Some(row) = snapshot
14095                    .buffer_snapshot
14096                    .buffer_line_for_row(MultiBufferRow(point.row))
14097                    .map(|(_, range)| range.start.row)
14098                else {
14099                    continue;
14100                };
14101
14102                let context_range =
14103                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14104                runnable_rows.push((
14105                    (runnable.buffer_id, row),
14106                    RunnableTasks {
14107                        templates: tasks,
14108                        offset: snapshot
14109                            .buffer_snapshot
14110                            .anchor_before(runnable.run_range.start),
14111                        context_range,
14112                        column: point.column,
14113                        extra_variables: runnable.extra_captures,
14114                    },
14115                ));
14116            }
14117            runnable_rows
14118        })
14119    }
14120
14121    fn templates_with_tags(
14122        project: &Entity<Project>,
14123        runnable: &mut Runnable,
14124        cx: &mut App,
14125    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14126        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14127            let (worktree_id, file) = project
14128                .buffer_for_id(runnable.buffer, cx)
14129                .and_then(|buffer| buffer.read(cx).file())
14130                .map(|file| (file.worktree_id(cx), file.clone()))
14131                .unzip();
14132
14133            (
14134                project.task_store().read(cx).task_inventory().cloned(),
14135                worktree_id,
14136                file,
14137            )
14138        });
14139
14140        let tags = mem::take(&mut runnable.tags);
14141        let language = runnable.language.clone();
14142        cx.spawn(async move |cx| {
14143            let mut templates_with_tags = Vec::new();
14144            if let Some(inventory) = inventory {
14145                for RunnableTag(tag) in tags {
14146                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14147                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14148                    }) else {
14149                        return templates_with_tags;
14150                    };
14151                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14152                        move |(_, template)| {
14153                            template.tags.iter().any(|source_tag| source_tag == &tag)
14154                        },
14155                    ));
14156                }
14157            }
14158            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14159
14160            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14161                // Strongest source wins; if we have worktree tag binding, prefer that to
14162                // global and language bindings;
14163                // if we have a global binding, prefer that to language binding.
14164                let first_mismatch = templates_with_tags
14165                    .iter()
14166                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14167                if let Some(index) = first_mismatch {
14168                    templates_with_tags.truncate(index);
14169                }
14170            }
14171
14172            templates_with_tags
14173        })
14174    }
14175
14176    pub fn move_to_enclosing_bracket(
14177        &mut self,
14178        _: &MoveToEnclosingBracket,
14179        window: &mut Window,
14180        cx: &mut Context<Self>,
14181    ) {
14182        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14183        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14184            s.move_offsets_with(|snapshot, selection| {
14185                let Some(enclosing_bracket_ranges) =
14186                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14187                else {
14188                    return;
14189                };
14190
14191                let mut best_length = usize::MAX;
14192                let mut best_inside = false;
14193                let mut best_in_bracket_range = false;
14194                let mut best_destination = None;
14195                for (open, close) in enclosing_bracket_ranges {
14196                    let close = close.to_inclusive();
14197                    let length = close.end() - open.start;
14198                    let inside = selection.start >= open.end && selection.end <= *close.start();
14199                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14200                        || close.contains(&selection.head());
14201
14202                    // If best is next to a bracket and current isn't, skip
14203                    if !in_bracket_range && best_in_bracket_range {
14204                        continue;
14205                    }
14206
14207                    // Prefer smaller lengths unless best is inside and current isn't
14208                    if length > best_length && (best_inside || !inside) {
14209                        continue;
14210                    }
14211
14212                    best_length = length;
14213                    best_inside = inside;
14214                    best_in_bracket_range = in_bracket_range;
14215                    best_destination = Some(
14216                        if close.contains(&selection.start) && close.contains(&selection.end) {
14217                            if inside { open.end } else { open.start }
14218                        } else if inside {
14219                            *close.start()
14220                        } else {
14221                            *close.end()
14222                        },
14223                    );
14224                }
14225
14226                if let Some(destination) = best_destination {
14227                    selection.collapse_to(destination, SelectionGoal::None);
14228                }
14229            })
14230        });
14231    }
14232
14233    pub fn undo_selection(
14234        &mut self,
14235        _: &UndoSelection,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) {
14239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14240        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14241            self.selection_history.mode = SelectionHistoryMode::Undoing;
14242            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14243                this.end_selection(window, cx);
14244                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14245                    s.select_anchors(entry.selections.to_vec())
14246                });
14247            });
14248            self.selection_history.mode = SelectionHistoryMode::Normal;
14249
14250            self.select_next_state = entry.select_next_state;
14251            self.select_prev_state = entry.select_prev_state;
14252            self.add_selections_state = entry.add_selections_state;
14253        }
14254    }
14255
14256    pub fn redo_selection(
14257        &mut self,
14258        _: &RedoSelection,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) {
14262        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14263        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14264            self.selection_history.mode = SelectionHistoryMode::Redoing;
14265            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14266                this.end_selection(window, cx);
14267                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14268                    s.select_anchors(entry.selections.to_vec())
14269                });
14270            });
14271            self.selection_history.mode = SelectionHistoryMode::Normal;
14272
14273            self.select_next_state = entry.select_next_state;
14274            self.select_prev_state = entry.select_prev_state;
14275            self.add_selections_state = entry.add_selections_state;
14276        }
14277    }
14278
14279    pub fn expand_excerpts(
14280        &mut self,
14281        action: &ExpandExcerpts,
14282        _: &mut Window,
14283        cx: &mut Context<Self>,
14284    ) {
14285        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14286    }
14287
14288    pub fn expand_excerpts_down(
14289        &mut self,
14290        action: &ExpandExcerptsDown,
14291        _: &mut Window,
14292        cx: &mut Context<Self>,
14293    ) {
14294        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14295    }
14296
14297    pub fn expand_excerpts_up(
14298        &mut self,
14299        action: &ExpandExcerptsUp,
14300        _: &mut Window,
14301        cx: &mut Context<Self>,
14302    ) {
14303        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14304    }
14305
14306    pub fn expand_excerpts_for_direction(
14307        &mut self,
14308        lines: u32,
14309        direction: ExpandExcerptDirection,
14310
14311        cx: &mut Context<Self>,
14312    ) {
14313        let selections = self.selections.disjoint_anchors();
14314
14315        let lines = if lines == 0 {
14316            EditorSettings::get_global(cx).expand_excerpt_lines
14317        } else {
14318            lines
14319        };
14320
14321        self.buffer.update(cx, |buffer, cx| {
14322            let snapshot = buffer.snapshot(cx);
14323            let mut excerpt_ids = selections
14324                .iter()
14325                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14326                .collect::<Vec<_>>();
14327            excerpt_ids.sort();
14328            excerpt_ids.dedup();
14329            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14330        })
14331    }
14332
14333    pub fn expand_excerpt(
14334        &mut self,
14335        excerpt: ExcerptId,
14336        direction: ExpandExcerptDirection,
14337        window: &mut Window,
14338        cx: &mut Context<Self>,
14339    ) {
14340        let current_scroll_position = self.scroll_position(cx);
14341        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14342        let mut should_scroll_up = false;
14343
14344        if direction == ExpandExcerptDirection::Down {
14345            let multi_buffer = self.buffer.read(cx);
14346            let snapshot = multi_buffer.snapshot(cx);
14347            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14348                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14349                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14350                        let buffer_snapshot = buffer.read(cx).snapshot();
14351                        let excerpt_end_row =
14352                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14353                        let last_row = buffer_snapshot.max_point().row;
14354                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14355                        should_scroll_up = lines_below >= lines_to_expand;
14356                    }
14357                }
14358            }
14359        }
14360
14361        self.buffer.update(cx, |buffer, cx| {
14362            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14363        });
14364
14365        if should_scroll_up {
14366            let new_scroll_position =
14367                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14368            self.set_scroll_position(new_scroll_position, window, cx);
14369        }
14370    }
14371
14372    pub fn go_to_singleton_buffer_point(
14373        &mut self,
14374        point: Point,
14375        window: &mut Window,
14376        cx: &mut Context<Self>,
14377    ) {
14378        self.go_to_singleton_buffer_range(point..point, window, cx);
14379    }
14380
14381    pub fn go_to_singleton_buffer_range(
14382        &mut self,
14383        range: Range<Point>,
14384        window: &mut Window,
14385        cx: &mut Context<Self>,
14386    ) {
14387        let multibuffer = self.buffer().read(cx);
14388        let Some(buffer) = multibuffer.as_singleton() else {
14389            return;
14390        };
14391        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14392            return;
14393        };
14394        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14395            return;
14396        };
14397        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14398            s.select_anchor_ranges([start..end])
14399        });
14400    }
14401
14402    pub fn go_to_diagnostic(
14403        &mut self,
14404        _: &GoToDiagnostic,
14405        window: &mut Window,
14406        cx: &mut Context<Self>,
14407    ) {
14408        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14409        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14410    }
14411
14412    pub fn go_to_prev_diagnostic(
14413        &mut self,
14414        _: &GoToPreviousDiagnostic,
14415        window: &mut Window,
14416        cx: &mut Context<Self>,
14417    ) {
14418        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14419        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14420    }
14421
14422    pub fn go_to_diagnostic_impl(
14423        &mut self,
14424        direction: Direction,
14425        window: &mut Window,
14426        cx: &mut Context<Self>,
14427    ) {
14428        let buffer = self.buffer.read(cx).snapshot(cx);
14429        let selection = self.selections.newest::<usize>(cx);
14430
14431        let mut active_group_id = None;
14432        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14433            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14434                active_group_id = Some(active_group.group_id);
14435            }
14436        }
14437
14438        fn filtered(
14439            snapshot: EditorSnapshot,
14440            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14441        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14442            diagnostics
14443                .filter(|entry| entry.range.start != entry.range.end)
14444                .filter(|entry| !entry.diagnostic.is_unnecessary)
14445                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14446        }
14447
14448        let snapshot = self.snapshot(window, cx);
14449        let before = filtered(
14450            snapshot.clone(),
14451            buffer
14452                .diagnostics_in_range(0..selection.start)
14453                .filter(|entry| entry.range.start <= selection.start),
14454        );
14455        let after = filtered(
14456            snapshot,
14457            buffer
14458                .diagnostics_in_range(selection.start..buffer.len())
14459                .filter(|entry| entry.range.start >= selection.start),
14460        );
14461
14462        let mut found: Option<DiagnosticEntry<usize>> = None;
14463        if direction == Direction::Prev {
14464            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14465            {
14466                for diagnostic in prev_diagnostics.into_iter().rev() {
14467                    if diagnostic.range.start != selection.start
14468                        || active_group_id
14469                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14470                    {
14471                        found = Some(diagnostic);
14472                        break 'outer;
14473                    }
14474                }
14475            }
14476        } else {
14477            for diagnostic in after.chain(before) {
14478                if diagnostic.range.start != selection.start
14479                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14480                {
14481                    found = Some(diagnostic);
14482                    break;
14483                }
14484            }
14485        }
14486        let Some(next_diagnostic) = found else {
14487            return;
14488        };
14489
14490        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14491            return;
14492        };
14493        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14494            s.select_ranges(vec![
14495                next_diagnostic.range.start..next_diagnostic.range.start,
14496            ])
14497        });
14498        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14499        self.refresh_inline_completion(false, true, window, cx);
14500    }
14501
14502    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14503        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14504        let snapshot = self.snapshot(window, cx);
14505        let selection = self.selections.newest::<Point>(cx);
14506        self.go_to_hunk_before_or_after_position(
14507            &snapshot,
14508            selection.head(),
14509            Direction::Next,
14510            window,
14511            cx,
14512        );
14513    }
14514
14515    pub fn go_to_hunk_before_or_after_position(
14516        &mut self,
14517        snapshot: &EditorSnapshot,
14518        position: Point,
14519        direction: Direction,
14520        window: &mut Window,
14521        cx: &mut Context<Editor>,
14522    ) {
14523        let row = if direction == Direction::Next {
14524            self.hunk_after_position(snapshot, position)
14525                .map(|hunk| hunk.row_range.start)
14526        } else {
14527            self.hunk_before_position(snapshot, position)
14528        };
14529
14530        if let Some(row) = row {
14531            let destination = Point::new(row.0, 0);
14532            let autoscroll = Autoscroll::center();
14533
14534            self.unfold_ranges(&[destination..destination], false, false, cx);
14535            self.change_selections(Some(autoscroll), window, cx, |s| {
14536                s.select_ranges([destination..destination]);
14537            });
14538        }
14539    }
14540
14541    fn hunk_after_position(
14542        &mut self,
14543        snapshot: &EditorSnapshot,
14544        position: Point,
14545    ) -> Option<MultiBufferDiffHunk> {
14546        snapshot
14547            .buffer_snapshot
14548            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14549            .find(|hunk| hunk.row_range.start.0 > position.row)
14550            .or_else(|| {
14551                snapshot
14552                    .buffer_snapshot
14553                    .diff_hunks_in_range(Point::zero()..position)
14554                    .find(|hunk| hunk.row_range.end.0 < position.row)
14555            })
14556    }
14557
14558    fn go_to_prev_hunk(
14559        &mut self,
14560        _: &GoToPreviousHunk,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14565        let snapshot = self.snapshot(window, cx);
14566        let selection = self.selections.newest::<Point>(cx);
14567        self.go_to_hunk_before_or_after_position(
14568            &snapshot,
14569            selection.head(),
14570            Direction::Prev,
14571            window,
14572            cx,
14573        );
14574    }
14575
14576    fn hunk_before_position(
14577        &mut self,
14578        snapshot: &EditorSnapshot,
14579        position: Point,
14580    ) -> Option<MultiBufferRow> {
14581        snapshot
14582            .buffer_snapshot
14583            .diff_hunk_before(position)
14584            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14585    }
14586
14587    fn go_to_next_change(
14588        &mut self,
14589        _: &GoToNextChange,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        if let Some(selections) = self
14594            .change_list
14595            .next_change(1, Direction::Next)
14596            .map(|s| s.to_vec())
14597        {
14598            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14599                let map = s.display_map();
14600                s.select_display_ranges(selections.iter().map(|a| {
14601                    let point = a.to_display_point(&map);
14602                    point..point
14603                }))
14604            })
14605        }
14606    }
14607
14608    fn go_to_previous_change(
14609        &mut self,
14610        _: &GoToPreviousChange,
14611        window: &mut Window,
14612        cx: &mut Context<Self>,
14613    ) {
14614        if let Some(selections) = self
14615            .change_list
14616            .next_change(1, Direction::Prev)
14617            .map(|s| s.to_vec())
14618        {
14619            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14620                let map = s.display_map();
14621                s.select_display_ranges(selections.iter().map(|a| {
14622                    let point = a.to_display_point(&map);
14623                    point..point
14624                }))
14625            })
14626        }
14627    }
14628
14629    fn go_to_line<T: 'static>(
14630        &mut self,
14631        position: Anchor,
14632        highlight_color: Option<Hsla>,
14633        window: &mut Window,
14634        cx: &mut Context<Self>,
14635    ) {
14636        let snapshot = self.snapshot(window, cx).display_snapshot;
14637        let position = position.to_point(&snapshot.buffer_snapshot);
14638        let start = snapshot
14639            .buffer_snapshot
14640            .clip_point(Point::new(position.row, 0), Bias::Left);
14641        let end = start + Point::new(1, 0);
14642        let start = snapshot.buffer_snapshot.anchor_before(start);
14643        let end = snapshot.buffer_snapshot.anchor_before(end);
14644
14645        self.highlight_rows::<T>(
14646            start..end,
14647            highlight_color
14648                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14649            Default::default(),
14650            cx,
14651        );
14652
14653        if self.buffer.read(cx).is_singleton() {
14654            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14655        }
14656    }
14657
14658    pub fn go_to_definition(
14659        &mut self,
14660        _: &GoToDefinition,
14661        window: &mut Window,
14662        cx: &mut Context<Self>,
14663    ) -> Task<Result<Navigated>> {
14664        let definition =
14665            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14666        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14667        cx.spawn_in(window, async move |editor, cx| {
14668            if definition.await? == Navigated::Yes {
14669                return Ok(Navigated::Yes);
14670            }
14671            match fallback_strategy {
14672                GoToDefinitionFallback::None => Ok(Navigated::No),
14673                GoToDefinitionFallback::FindAllReferences => {
14674                    match editor.update_in(cx, |editor, window, cx| {
14675                        editor.find_all_references(&FindAllReferences, window, cx)
14676                    })? {
14677                        Some(references) => references.await,
14678                        None => Ok(Navigated::No),
14679                    }
14680                }
14681            }
14682        })
14683    }
14684
14685    pub fn go_to_declaration(
14686        &mut self,
14687        _: &GoToDeclaration,
14688        window: &mut Window,
14689        cx: &mut Context<Self>,
14690    ) -> Task<Result<Navigated>> {
14691        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14692    }
14693
14694    pub fn go_to_declaration_split(
14695        &mut self,
14696        _: &GoToDeclaration,
14697        window: &mut Window,
14698        cx: &mut Context<Self>,
14699    ) -> Task<Result<Navigated>> {
14700        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14701    }
14702
14703    pub fn go_to_implementation(
14704        &mut self,
14705        _: &GoToImplementation,
14706        window: &mut Window,
14707        cx: &mut Context<Self>,
14708    ) -> Task<Result<Navigated>> {
14709        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14710    }
14711
14712    pub fn go_to_implementation_split(
14713        &mut self,
14714        _: &GoToImplementationSplit,
14715        window: &mut Window,
14716        cx: &mut Context<Self>,
14717    ) -> Task<Result<Navigated>> {
14718        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14719    }
14720
14721    pub fn go_to_type_definition(
14722        &mut self,
14723        _: &GoToTypeDefinition,
14724        window: &mut Window,
14725        cx: &mut Context<Self>,
14726    ) -> Task<Result<Navigated>> {
14727        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14728    }
14729
14730    pub fn go_to_definition_split(
14731        &mut self,
14732        _: &GoToDefinitionSplit,
14733        window: &mut Window,
14734        cx: &mut Context<Self>,
14735    ) -> Task<Result<Navigated>> {
14736        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14737    }
14738
14739    pub fn go_to_type_definition_split(
14740        &mut self,
14741        _: &GoToTypeDefinitionSplit,
14742        window: &mut Window,
14743        cx: &mut Context<Self>,
14744    ) -> Task<Result<Navigated>> {
14745        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14746    }
14747
14748    fn go_to_definition_of_kind(
14749        &mut self,
14750        kind: GotoDefinitionKind,
14751        split: bool,
14752        window: &mut Window,
14753        cx: &mut Context<Self>,
14754    ) -> Task<Result<Navigated>> {
14755        let Some(provider) = self.semantics_provider.clone() else {
14756            return Task::ready(Ok(Navigated::No));
14757        };
14758        let head = self.selections.newest::<usize>(cx).head();
14759        let buffer = self.buffer.read(cx);
14760        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14761            text_anchor
14762        } else {
14763            return Task::ready(Ok(Navigated::No));
14764        };
14765
14766        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14767            return Task::ready(Ok(Navigated::No));
14768        };
14769
14770        cx.spawn_in(window, async move |editor, cx| {
14771            let definitions = definitions.await?;
14772            let navigated = editor
14773                .update_in(cx, |editor, window, cx| {
14774                    editor.navigate_to_hover_links(
14775                        Some(kind),
14776                        definitions
14777                            .into_iter()
14778                            .filter(|location| {
14779                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14780                            })
14781                            .map(HoverLink::Text)
14782                            .collect::<Vec<_>>(),
14783                        split,
14784                        window,
14785                        cx,
14786                    )
14787                })?
14788                .await?;
14789            anyhow::Ok(navigated)
14790        })
14791    }
14792
14793    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14794        let selection = self.selections.newest_anchor();
14795        let head = selection.head();
14796        let tail = selection.tail();
14797
14798        let Some((buffer, start_position)) =
14799            self.buffer.read(cx).text_anchor_for_position(head, cx)
14800        else {
14801            return;
14802        };
14803
14804        let end_position = if head != tail {
14805            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14806                return;
14807            };
14808            Some(pos)
14809        } else {
14810            None
14811        };
14812
14813        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14814            let url = if let Some(end_pos) = end_position {
14815                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14816            } else {
14817                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14818            };
14819
14820            if let Some(url) = url {
14821                editor.update(cx, |_, cx| {
14822                    cx.open_url(&url);
14823                })
14824            } else {
14825                Ok(())
14826            }
14827        });
14828
14829        url_finder.detach();
14830    }
14831
14832    pub fn open_selected_filename(
14833        &mut self,
14834        _: &OpenSelectedFilename,
14835        window: &mut Window,
14836        cx: &mut Context<Self>,
14837    ) {
14838        let Some(workspace) = self.workspace() else {
14839            return;
14840        };
14841
14842        let position = self.selections.newest_anchor().head();
14843
14844        let Some((buffer, buffer_position)) =
14845            self.buffer.read(cx).text_anchor_for_position(position, cx)
14846        else {
14847            return;
14848        };
14849
14850        let project = self.project.clone();
14851
14852        cx.spawn_in(window, async move |_, cx| {
14853            let result = find_file(&buffer, project, buffer_position, cx).await;
14854
14855            if let Some((_, path)) = result {
14856                workspace
14857                    .update_in(cx, |workspace, window, cx| {
14858                        workspace.open_resolved_path(path, window, cx)
14859                    })?
14860                    .await?;
14861            }
14862            anyhow::Ok(())
14863        })
14864        .detach();
14865    }
14866
14867    pub(crate) fn navigate_to_hover_links(
14868        &mut self,
14869        kind: Option<GotoDefinitionKind>,
14870        mut definitions: Vec<HoverLink>,
14871        split: bool,
14872        window: &mut Window,
14873        cx: &mut Context<Editor>,
14874    ) -> Task<Result<Navigated>> {
14875        // If there is one definition, just open it directly
14876        if definitions.len() == 1 {
14877            let definition = definitions.pop().unwrap();
14878
14879            enum TargetTaskResult {
14880                Location(Option<Location>),
14881                AlreadyNavigated,
14882            }
14883
14884            let target_task = match definition {
14885                HoverLink::Text(link) => {
14886                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14887                }
14888                HoverLink::InlayHint(lsp_location, server_id) => {
14889                    let computation =
14890                        self.compute_target_location(lsp_location, server_id, window, cx);
14891                    cx.background_spawn(async move {
14892                        let location = computation.await?;
14893                        Ok(TargetTaskResult::Location(location))
14894                    })
14895                }
14896                HoverLink::Url(url) => {
14897                    cx.open_url(&url);
14898                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14899                }
14900                HoverLink::File(path) => {
14901                    if let Some(workspace) = self.workspace() {
14902                        cx.spawn_in(window, async move |_, cx| {
14903                            workspace
14904                                .update_in(cx, |workspace, window, cx| {
14905                                    workspace.open_resolved_path(path, window, cx)
14906                                })?
14907                                .await
14908                                .map(|_| TargetTaskResult::AlreadyNavigated)
14909                        })
14910                    } else {
14911                        Task::ready(Ok(TargetTaskResult::Location(None)))
14912                    }
14913                }
14914            };
14915            cx.spawn_in(window, async move |editor, cx| {
14916                let target = match target_task.await.context("target resolution task")? {
14917                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14918                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14919                    TargetTaskResult::Location(Some(target)) => target,
14920                };
14921
14922                editor.update_in(cx, |editor, window, cx| {
14923                    let Some(workspace) = editor.workspace() else {
14924                        return Navigated::No;
14925                    };
14926                    let pane = workspace.read(cx).active_pane().clone();
14927
14928                    let range = target.range.to_point(target.buffer.read(cx));
14929                    let range = editor.range_for_match(&range);
14930                    let range = collapse_multiline_range(range);
14931
14932                    if !split
14933                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14934                    {
14935                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14936                    } else {
14937                        window.defer(cx, move |window, cx| {
14938                            let target_editor: Entity<Self> =
14939                                workspace.update(cx, |workspace, cx| {
14940                                    let pane = if split {
14941                                        workspace.adjacent_pane(window, cx)
14942                                    } else {
14943                                        workspace.active_pane().clone()
14944                                    };
14945
14946                                    workspace.open_project_item(
14947                                        pane,
14948                                        target.buffer.clone(),
14949                                        true,
14950                                        true,
14951                                        window,
14952                                        cx,
14953                                    )
14954                                });
14955                            target_editor.update(cx, |target_editor, cx| {
14956                                // When selecting a definition in a different buffer, disable the nav history
14957                                // to avoid creating a history entry at the previous cursor location.
14958                                pane.update(cx, |pane, _| pane.disable_history());
14959                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14960                                pane.update(cx, |pane, _| pane.enable_history());
14961                            });
14962                        });
14963                    }
14964                    Navigated::Yes
14965                })
14966            })
14967        } else if !definitions.is_empty() {
14968            cx.spawn_in(window, async move |editor, cx| {
14969                let (title, location_tasks, workspace) = editor
14970                    .update_in(cx, |editor, window, cx| {
14971                        let tab_kind = match kind {
14972                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14973                            _ => "Definitions",
14974                        };
14975                        let title = definitions
14976                            .iter()
14977                            .find_map(|definition| match definition {
14978                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14979                                    let buffer = origin.buffer.read(cx);
14980                                    format!(
14981                                        "{} for {}",
14982                                        tab_kind,
14983                                        buffer
14984                                            .text_for_range(origin.range.clone())
14985                                            .collect::<String>()
14986                                    )
14987                                }),
14988                                HoverLink::InlayHint(_, _) => None,
14989                                HoverLink::Url(_) => None,
14990                                HoverLink::File(_) => None,
14991                            })
14992                            .unwrap_or(tab_kind.to_string());
14993                        let location_tasks = definitions
14994                            .into_iter()
14995                            .map(|definition| match definition {
14996                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14997                                HoverLink::InlayHint(lsp_location, server_id) => editor
14998                                    .compute_target_location(lsp_location, server_id, window, cx),
14999                                HoverLink::Url(_) => Task::ready(Ok(None)),
15000                                HoverLink::File(_) => Task::ready(Ok(None)),
15001                            })
15002                            .collect::<Vec<_>>();
15003                        (title, location_tasks, editor.workspace().clone())
15004                    })
15005                    .context("location tasks preparation")?;
15006
15007                let locations = future::join_all(location_tasks)
15008                    .await
15009                    .into_iter()
15010                    .filter_map(|location| location.transpose())
15011                    .collect::<Result<_>>()
15012                    .context("location tasks")?;
15013
15014                let Some(workspace) = workspace else {
15015                    return Ok(Navigated::No);
15016                };
15017                let opened = workspace
15018                    .update_in(cx, |workspace, window, cx| {
15019                        Self::open_locations_in_multibuffer(
15020                            workspace,
15021                            locations,
15022                            title,
15023                            split,
15024                            MultibufferSelectionMode::First,
15025                            window,
15026                            cx,
15027                        )
15028                    })
15029                    .ok();
15030
15031                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15032            })
15033        } else {
15034            Task::ready(Ok(Navigated::No))
15035        }
15036    }
15037
15038    fn compute_target_location(
15039        &self,
15040        lsp_location: lsp::Location,
15041        server_id: LanguageServerId,
15042        window: &mut Window,
15043        cx: &mut Context<Self>,
15044    ) -> Task<anyhow::Result<Option<Location>>> {
15045        let Some(project) = self.project.clone() else {
15046            return Task::ready(Ok(None));
15047        };
15048
15049        cx.spawn_in(window, async move |editor, cx| {
15050            let location_task = editor.update(cx, |_, cx| {
15051                project.update(cx, |project, cx| {
15052                    let language_server_name = project
15053                        .language_server_statuses(cx)
15054                        .find(|(id, _)| server_id == *id)
15055                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15056                    language_server_name.map(|language_server_name| {
15057                        project.open_local_buffer_via_lsp(
15058                            lsp_location.uri.clone(),
15059                            server_id,
15060                            language_server_name,
15061                            cx,
15062                        )
15063                    })
15064                })
15065            })?;
15066            let location = match location_task {
15067                Some(task) => Some({
15068                    let target_buffer_handle = task.await.context("open local buffer")?;
15069                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15070                        let target_start = target_buffer
15071                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15072                        let target_end = target_buffer
15073                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15074                        target_buffer.anchor_after(target_start)
15075                            ..target_buffer.anchor_before(target_end)
15076                    })?;
15077                    Location {
15078                        buffer: target_buffer_handle,
15079                        range,
15080                    }
15081                }),
15082                None => None,
15083            };
15084            Ok(location)
15085        })
15086    }
15087
15088    pub fn find_all_references(
15089        &mut self,
15090        _: &FindAllReferences,
15091        window: &mut Window,
15092        cx: &mut Context<Self>,
15093    ) -> Option<Task<Result<Navigated>>> {
15094        let selection = self.selections.newest::<usize>(cx);
15095        let multi_buffer = self.buffer.read(cx);
15096        let head = selection.head();
15097
15098        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15099        let head_anchor = multi_buffer_snapshot.anchor_at(
15100            head,
15101            if head < selection.tail() {
15102                Bias::Right
15103            } else {
15104                Bias::Left
15105            },
15106        );
15107
15108        match self
15109            .find_all_references_task_sources
15110            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15111        {
15112            Ok(_) => {
15113                log::info!(
15114                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15115                );
15116                return None;
15117            }
15118            Err(i) => {
15119                self.find_all_references_task_sources.insert(i, head_anchor);
15120            }
15121        }
15122
15123        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15124        let workspace = self.workspace()?;
15125        let project = workspace.read(cx).project().clone();
15126        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15127        Some(cx.spawn_in(window, async move |editor, cx| {
15128            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15129                if let Ok(i) = editor
15130                    .find_all_references_task_sources
15131                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15132                {
15133                    editor.find_all_references_task_sources.remove(i);
15134                }
15135            });
15136
15137            let locations = references.await?;
15138            if locations.is_empty() {
15139                return anyhow::Ok(Navigated::No);
15140            }
15141
15142            workspace.update_in(cx, |workspace, window, cx| {
15143                let title = locations
15144                    .first()
15145                    .as_ref()
15146                    .map(|location| {
15147                        let buffer = location.buffer.read(cx);
15148                        format!(
15149                            "References to `{}`",
15150                            buffer
15151                                .text_for_range(location.range.clone())
15152                                .collect::<String>()
15153                        )
15154                    })
15155                    .unwrap();
15156                Self::open_locations_in_multibuffer(
15157                    workspace,
15158                    locations,
15159                    title,
15160                    false,
15161                    MultibufferSelectionMode::First,
15162                    window,
15163                    cx,
15164                );
15165                Navigated::Yes
15166            })
15167        }))
15168    }
15169
15170    /// Opens a multibuffer with the given project locations in it
15171    pub fn open_locations_in_multibuffer(
15172        workspace: &mut Workspace,
15173        mut locations: Vec<Location>,
15174        title: String,
15175        split: bool,
15176        multibuffer_selection_mode: MultibufferSelectionMode,
15177        window: &mut Window,
15178        cx: &mut Context<Workspace>,
15179    ) {
15180        // If there are multiple definitions, open them in a multibuffer
15181        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15182        let mut locations = locations.into_iter().peekable();
15183        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15184        let capability = workspace.project().read(cx).capability();
15185
15186        let excerpt_buffer = cx.new(|cx| {
15187            let mut multibuffer = MultiBuffer::new(capability);
15188            while let Some(location) = locations.next() {
15189                let buffer = location.buffer.read(cx);
15190                let mut ranges_for_buffer = Vec::new();
15191                let range = location.range.to_point(buffer);
15192                ranges_for_buffer.push(range.clone());
15193
15194                while let Some(next_location) = locations.peek() {
15195                    if next_location.buffer == location.buffer {
15196                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15197                        locations.next();
15198                    } else {
15199                        break;
15200                    }
15201                }
15202
15203                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15204                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15205                    PathKey::for_buffer(&location.buffer, cx),
15206                    location.buffer.clone(),
15207                    ranges_for_buffer,
15208                    DEFAULT_MULTIBUFFER_CONTEXT,
15209                    cx,
15210                );
15211                ranges.extend(new_ranges)
15212            }
15213
15214            multibuffer.with_title(title)
15215        });
15216
15217        let editor = cx.new(|cx| {
15218            Editor::for_multibuffer(
15219                excerpt_buffer,
15220                Some(workspace.project().clone()),
15221                window,
15222                cx,
15223            )
15224        });
15225        editor.update(cx, |editor, cx| {
15226            match multibuffer_selection_mode {
15227                MultibufferSelectionMode::First => {
15228                    if let Some(first_range) = ranges.first() {
15229                        editor.change_selections(None, window, cx, |selections| {
15230                            selections.clear_disjoint();
15231                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15232                        });
15233                    }
15234                    editor.highlight_background::<Self>(
15235                        &ranges,
15236                        |theme| theme.editor_highlighted_line_background,
15237                        cx,
15238                    );
15239                }
15240                MultibufferSelectionMode::All => {
15241                    editor.change_selections(None, window, cx, |selections| {
15242                        selections.clear_disjoint();
15243                        selections.select_anchor_ranges(ranges);
15244                    });
15245                }
15246            }
15247            editor.register_buffers_with_language_servers(cx);
15248        });
15249
15250        let item = Box::new(editor);
15251        let item_id = item.item_id();
15252
15253        if split {
15254            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15255        } else {
15256            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15257                let (preview_item_id, preview_item_idx) =
15258                    workspace.active_pane().read_with(cx, |pane, _| {
15259                        (pane.preview_item_id(), pane.preview_item_idx())
15260                    });
15261
15262                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15263
15264                if let Some(preview_item_id) = preview_item_id {
15265                    workspace.active_pane().update(cx, |pane, cx| {
15266                        pane.remove_item(preview_item_id, false, false, window, cx);
15267                    });
15268                }
15269            } else {
15270                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15271            }
15272        }
15273        workspace.active_pane().update(cx, |pane, cx| {
15274            pane.set_preview_item_id(Some(item_id), cx);
15275        });
15276    }
15277
15278    pub fn rename(
15279        &mut self,
15280        _: &Rename,
15281        window: &mut Window,
15282        cx: &mut Context<Self>,
15283    ) -> Option<Task<Result<()>>> {
15284        use language::ToOffset as _;
15285
15286        let provider = self.semantics_provider.clone()?;
15287        let selection = self.selections.newest_anchor().clone();
15288        let (cursor_buffer, cursor_buffer_position) = self
15289            .buffer
15290            .read(cx)
15291            .text_anchor_for_position(selection.head(), cx)?;
15292        let (tail_buffer, cursor_buffer_position_end) = self
15293            .buffer
15294            .read(cx)
15295            .text_anchor_for_position(selection.tail(), cx)?;
15296        if tail_buffer != cursor_buffer {
15297            return None;
15298        }
15299
15300        let snapshot = cursor_buffer.read(cx).snapshot();
15301        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15302        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15303        let prepare_rename = provider
15304            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15305            .unwrap_or_else(|| Task::ready(Ok(None)));
15306        drop(snapshot);
15307
15308        Some(cx.spawn_in(window, async move |this, cx| {
15309            let rename_range = if let Some(range) = prepare_rename.await? {
15310                Some(range)
15311            } else {
15312                this.update(cx, |this, cx| {
15313                    let buffer = this.buffer.read(cx).snapshot(cx);
15314                    let mut buffer_highlights = this
15315                        .document_highlights_for_position(selection.head(), &buffer)
15316                        .filter(|highlight| {
15317                            highlight.start.excerpt_id == selection.head().excerpt_id
15318                                && highlight.end.excerpt_id == selection.head().excerpt_id
15319                        });
15320                    buffer_highlights
15321                        .next()
15322                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15323                })?
15324            };
15325            if let Some(rename_range) = rename_range {
15326                this.update_in(cx, |this, window, cx| {
15327                    let snapshot = cursor_buffer.read(cx).snapshot();
15328                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15329                    let cursor_offset_in_rename_range =
15330                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15331                    let cursor_offset_in_rename_range_end =
15332                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15333
15334                    this.take_rename(false, window, cx);
15335                    let buffer = this.buffer.read(cx).read(cx);
15336                    let cursor_offset = selection.head().to_offset(&buffer);
15337                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15338                    let rename_end = rename_start + rename_buffer_range.len();
15339                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15340                    let mut old_highlight_id = None;
15341                    let old_name: Arc<str> = buffer
15342                        .chunks(rename_start..rename_end, true)
15343                        .map(|chunk| {
15344                            if old_highlight_id.is_none() {
15345                                old_highlight_id = chunk.syntax_highlight_id;
15346                            }
15347                            chunk.text
15348                        })
15349                        .collect::<String>()
15350                        .into();
15351
15352                    drop(buffer);
15353
15354                    // Position the selection in the rename editor so that it matches the current selection.
15355                    this.show_local_selections = false;
15356                    let rename_editor = cx.new(|cx| {
15357                        let mut editor = Editor::single_line(window, cx);
15358                        editor.buffer.update(cx, |buffer, cx| {
15359                            buffer.edit([(0..0, old_name.clone())], None, cx)
15360                        });
15361                        let rename_selection_range = match cursor_offset_in_rename_range
15362                            .cmp(&cursor_offset_in_rename_range_end)
15363                        {
15364                            Ordering::Equal => {
15365                                editor.select_all(&SelectAll, window, cx);
15366                                return editor;
15367                            }
15368                            Ordering::Less => {
15369                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15370                            }
15371                            Ordering::Greater => {
15372                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15373                            }
15374                        };
15375                        if rename_selection_range.end > old_name.len() {
15376                            editor.select_all(&SelectAll, window, cx);
15377                        } else {
15378                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15379                                s.select_ranges([rename_selection_range]);
15380                            });
15381                        }
15382                        editor
15383                    });
15384                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15385                        if e == &EditorEvent::Focused {
15386                            cx.emit(EditorEvent::FocusedIn)
15387                        }
15388                    })
15389                    .detach();
15390
15391                    let write_highlights =
15392                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15393                    let read_highlights =
15394                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15395                    let ranges = write_highlights
15396                        .iter()
15397                        .flat_map(|(_, ranges)| ranges.iter())
15398                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15399                        .cloned()
15400                        .collect();
15401
15402                    this.highlight_text::<Rename>(
15403                        ranges,
15404                        HighlightStyle {
15405                            fade_out: Some(0.6),
15406                            ..Default::default()
15407                        },
15408                        cx,
15409                    );
15410                    let rename_focus_handle = rename_editor.focus_handle(cx);
15411                    window.focus(&rename_focus_handle);
15412                    let block_id = this.insert_blocks(
15413                        [BlockProperties {
15414                            style: BlockStyle::Flex,
15415                            placement: BlockPlacement::Below(range.start),
15416                            height: Some(1),
15417                            render: Arc::new({
15418                                let rename_editor = rename_editor.clone();
15419                                move |cx: &mut BlockContext| {
15420                                    let mut text_style = cx.editor_style.text.clone();
15421                                    if let Some(highlight_style) = old_highlight_id
15422                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15423                                    {
15424                                        text_style = text_style.highlight(highlight_style);
15425                                    }
15426                                    div()
15427                                        .block_mouse_except_scroll()
15428                                        .pl(cx.anchor_x)
15429                                        .child(EditorElement::new(
15430                                            &rename_editor,
15431                                            EditorStyle {
15432                                                background: cx.theme().system().transparent,
15433                                                local_player: cx.editor_style.local_player,
15434                                                text: text_style,
15435                                                scrollbar_width: cx.editor_style.scrollbar_width,
15436                                                syntax: cx.editor_style.syntax.clone(),
15437                                                status: cx.editor_style.status.clone(),
15438                                                inlay_hints_style: HighlightStyle {
15439                                                    font_weight: Some(FontWeight::BOLD),
15440                                                    ..make_inlay_hints_style(cx.app)
15441                                                },
15442                                                inline_completion_styles: make_suggestion_styles(
15443                                                    cx.app,
15444                                                ),
15445                                                ..EditorStyle::default()
15446                                            },
15447                                        ))
15448                                        .into_any_element()
15449                                }
15450                            }),
15451                            priority: 0,
15452                            render_in_minimap: true,
15453                        }],
15454                        Some(Autoscroll::fit()),
15455                        cx,
15456                    )[0];
15457                    this.pending_rename = Some(RenameState {
15458                        range,
15459                        old_name,
15460                        editor: rename_editor,
15461                        block_id,
15462                    });
15463                })?;
15464            }
15465
15466            Ok(())
15467        }))
15468    }
15469
15470    pub fn confirm_rename(
15471        &mut self,
15472        _: &ConfirmRename,
15473        window: &mut Window,
15474        cx: &mut Context<Self>,
15475    ) -> Option<Task<Result<()>>> {
15476        let rename = self.take_rename(false, window, cx)?;
15477        let workspace = self.workspace()?.downgrade();
15478        let (buffer, start) = self
15479            .buffer
15480            .read(cx)
15481            .text_anchor_for_position(rename.range.start, cx)?;
15482        let (end_buffer, _) = self
15483            .buffer
15484            .read(cx)
15485            .text_anchor_for_position(rename.range.end, cx)?;
15486        if buffer != end_buffer {
15487            return None;
15488        }
15489
15490        let old_name = rename.old_name;
15491        let new_name = rename.editor.read(cx).text(cx);
15492
15493        let rename = self.semantics_provider.as_ref()?.perform_rename(
15494            &buffer,
15495            start,
15496            new_name.clone(),
15497            cx,
15498        )?;
15499
15500        Some(cx.spawn_in(window, async move |editor, cx| {
15501            let project_transaction = rename.await?;
15502            Self::open_project_transaction(
15503                &editor,
15504                workspace,
15505                project_transaction,
15506                format!("Rename: {}{}", old_name, new_name),
15507                cx,
15508            )
15509            .await?;
15510
15511            editor.update(cx, |editor, cx| {
15512                editor.refresh_document_highlights(cx);
15513            })?;
15514            Ok(())
15515        }))
15516    }
15517
15518    fn take_rename(
15519        &mut self,
15520        moving_cursor: bool,
15521        window: &mut Window,
15522        cx: &mut Context<Self>,
15523    ) -> Option<RenameState> {
15524        let rename = self.pending_rename.take()?;
15525        if rename.editor.focus_handle(cx).is_focused(window) {
15526            window.focus(&self.focus_handle);
15527        }
15528
15529        self.remove_blocks(
15530            [rename.block_id].into_iter().collect(),
15531            Some(Autoscroll::fit()),
15532            cx,
15533        );
15534        self.clear_highlights::<Rename>(cx);
15535        self.show_local_selections = true;
15536
15537        if moving_cursor {
15538            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15539                editor.selections.newest::<usize>(cx).head()
15540            });
15541
15542            // Update the selection to match the position of the selection inside
15543            // the rename editor.
15544            let snapshot = self.buffer.read(cx).read(cx);
15545            let rename_range = rename.range.to_offset(&snapshot);
15546            let cursor_in_editor = snapshot
15547                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15548                .min(rename_range.end);
15549            drop(snapshot);
15550
15551            self.change_selections(None, window, cx, |s| {
15552                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15553            });
15554        } else {
15555            self.refresh_document_highlights(cx);
15556        }
15557
15558        Some(rename)
15559    }
15560
15561    pub fn pending_rename(&self) -> Option<&RenameState> {
15562        self.pending_rename.as_ref()
15563    }
15564
15565    fn format(
15566        &mut self,
15567        _: &Format,
15568        window: &mut Window,
15569        cx: &mut Context<Self>,
15570    ) -> Option<Task<Result<()>>> {
15571        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15572
15573        let project = match &self.project {
15574            Some(project) => project.clone(),
15575            None => return None,
15576        };
15577
15578        Some(self.perform_format(
15579            project,
15580            FormatTrigger::Manual,
15581            FormatTarget::Buffers,
15582            window,
15583            cx,
15584        ))
15585    }
15586
15587    fn format_selections(
15588        &mut self,
15589        _: &FormatSelections,
15590        window: &mut Window,
15591        cx: &mut Context<Self>,
15592    ) -> Option<Task<Result<()>>> {
15593        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15594
15595        let project = match &self.project {
15596            Some(project) => project.clone(),
15597            None => return None,
15598        };
15599
15600        let ranges = self
15601            .selections
15602            .all_adjusted(cx)
15603            .into_iter()
15604            .map(|selection| selection.range())
15605            .collect_vec();
15606
15607        Some(self.perform_format(
15608            project,
15609            FormatTrigger::Manual,
15610            FormatTarget::Ranges(ranges),
15611            window,
15612            cx,
15613        ))
15614    }
15615
15616    fn perform_format(
15617        &mut self,
15618        project: Entity<Project>,
15619        trigger: FormatTrigger,
15620        target: FormatTarget,
15621        window: &mut Window,
15622        cx: &mut Context<Self>,
15623    ) -> Task<Result<()>> {
15624        let buffer = self.buffer.clone();
15625        let (buffers, target) = match target {
15626            FormatTarget::Buffers => {
15627                let mut buffers = buffer.read(cx).all_buffers();
15628                if trigger == FormatTrigger::Save {
15629                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15630                }
15631                (buffers, LspFormatTarget::Buffers)
15632            }
15633            FormatTarget::Ranges(selection_ranges) => {
15634                let multi_buffer = buffer.read(cx);
15635                let snapshot = multi_buffer.read(cx);
15636                let mut buffers = HashSet::default();
15637                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15638                    BTreeMap::new();
15639                for selection_range in selection_ranges {
15640                    for (buffer, buffer_range, _) in
15641                        snapshot.range_to_buffer_ranges(selection_range)
15642                    {
15643                        let buffer_id = buffer.remote_id();
15644                        let start = buffer.anchor_before(buffer_range.start);
15645                        let end = buffer.anchor_after(buffer_range.end);
15646                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15647                        buffer_id_to_ranges
15648                            .entry(buffer_id)
15649                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15650                            .or_insert_with(|| vec![start..end]);
15651                    }
15652                }
15653                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15654            }
15655        };
15656
15657        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15658        let selections_prev = transaction_id_prev
15659            .and_then(|transaction_id_prev| {
15660                // default to selections as they were after the last edit, if we have them,
15661                // instead of how they are now.
15662                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15663                // will take you back to where you made the last edit, instead of staying where you scrolled
15664                self.selection_history
15665                    .transaction(transaction_id_prev)
15666                    .map(|t| t.0.clone())
15667            })
15668            .unwrap_or_else(|| {
15669                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15670                self.selections.disjoint_anchors()
15671            });
15672
15673        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15674        let format = project.update(cx, |project, cx| {
15675            project.format(buffers, target, true, trigger, cx)
15676        });
15677
15678        cx.spawn_in(window, async move |editor, cx| {
15679            let transaction = futures::select_biased! {
15680                transaction = format.log_err().fuse() => transaction,
15681                () = timeout => {
15682                    log::warn!("timed out waiting for formatting");
15683                    None
15684                }
15685            };
15686
15687            buffer
15688                .update(cx, |buffer, cx| {
15689                    if let Some(transaction) = transaction {
15690                        if !buffer.is_singleton() {
15691                            buffer.push_transaction(&transaction.0, cx);
15692                        }
15693                    }
15694                    cx.notify();
15695                })
15696                .ok();
15697
15698            if let Some(transaction_id_now) =
15699                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15700            {
15701                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15702                if has_new_transaction {
15703                    _ = editor.update(cx, |editor, _| {
15704                        editor
15705                            .selection_history
15706                            .insert_transaction(transaction_id_now, selections_prev);
15707                    });
15708                }
15709            }
15710
15711            Ok(())
15712        })
15713    }
15714
15715    fn organize_imports(
15716        &mut self,
15717        _: &OrganizeImports,
15718        window: &mut Window,
15719        cx: &mut Context<Self>,
15720    ) -> Option<Task<Result<()>>> {
15721        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15722        let project = match &self.project {
15723            Some(project) => project.clone(),
15724            None => return None,
15725        };
15726        Some(self.perform_code_action_kind(
15727            project,
15728            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15729            window,
15730            cx,
15731        ))
15732    }
15733
15734    fn perform_code_action_kind(
15735        &mut self,
15736        project: Entity<Project>,
15737        kind: CodeActionKind,
15738        window: &mut Window,
15739        cx: &mut Context<Self>,
15740    ) -> Task<Result<()>> {
15741        let buffer = self.buffer.clone();
15742        let buffers = buffer.read(cx).all_buffers();
15743        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15744        let apply_action = project.update(cx, |project, cx| {
15745            project.apply_code_action_kind(buffers, kind, true, cx)
15746        });
15747        cx.spawn_in(window, async move |_, cx| {
15748            let transaction = futures::select_biased! {
15749                () = timeout => {
15750                    log::warn!("timed out waiting for executing code action");
15751                    None
15752                }
15753                transaction = apply_action.log_err().fuse() => transaction,
15754            };
15755            buffer
15756                .update(cx, |buffer, cx| {
15757                    // check if we need this
15758                    if let Some(transaction) = transaction {
15759                        if !buffer.is_singleton() {
15760                            buffer.push_transaction(&transaction.0, cx);
15761                        }
15762                    }
15763                    cx.notify();
15764                })
15765                .ok();
15766            Ok(())
15767        })
15768    }
15769
15770    fn restart_language_server(
15771        &mut self,
15772        _: &RestartLanguageServer,
15773        _: &mut Window,
15774        cx: &mut Context<Self>,
15775    ) {
15776        if let Some(project) = self.project.clone() {
15777            self.buffer.update(cx, |multi_buffer, cx| {
15778                project.update(cx, |project, cx| {
15779                    project.restart_language_servers_for_buffers(
15780                        multi_buffer.all_buffers().into_iter().collect(),
15781                        cx,
15782                    );
15783                });
15784            })
15785        }
15786    }
15787
15788    fn stop_language_server(
15789        &mut self,
15790        _: &StopLanguageServer,
15791        _: &mut Window,
15792        cx: &mut Context<Self>,
15793    ) {
15794        if let Some(project) = self.project.clone() {
15795            self.buffer.update(cx, |multi_buffer, cx| {
15796                project.update(cx, |project, cx| {
15797                    project.stop_language_servers_for_buffers(
15798                        multi_buffer.all_buffers().into_iter().collect(),
15799                        cx,
15800                    );
15801                    cx.emit(project::Event::RefreshInlayHints);
15802                });
15803            });
15804        }
15805    }
15806
15807    fn cancel_language_server_work(
15808        workspace: &mut Workspace,
15809        _: &actions::CancelLanguageServerWork,
15810        _: &mut Window,
15811        cx: &mut Context<Workspace>,
15812    ) {
15813        let project = workspace.project();
15814        let buffers = workspace
15815            .active_item(cx)
15816            .and_then(|item| item.act_as::<Editor>(cx))
15817            .map_or(HashSet::default(), |editor| {
15818                editor.read(cx).buffer.read(cx).all_buffers()
15819            });
15820        project.update(cx, |project, cx| {
15821            project.cancel_language_server_work_for_buffers(buffers, cx);
15822        });
15823    }
15824
15825    fn show_character_palette(
15826        &mut self,
15827        _: &ShowCharacterPalette,
15828        window: &mut Window,
15829        _: &mut Context<Self>,
15830    ) {
15831        window.show_character_palette();
15832    }
15833
15834    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15835        if self.mode.is_minimap() {
15836            return;
15837        }
15838
15839        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15840            let buffer = self.buffer.read(cx).snapshot(cx);
15841            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15842            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15843            let is_valid = buffer
15844                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15845                .any(|entry| {
15846                    entry.diagnostic.is_primary
15847                        && !entry.range.is_empty()
15848                        && entry.range.start == primary_range_start
15849                        && entry.diagnostic.message == active_diagnostics.active_message
15850                });
15851
15852            if !is_valid {
15853                self.dismiss_diagnostics(cx);
15854            }
15855        }
15856    }
15857
15858    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15859        match &self.active_diagnostics {
15860            ActiveDiagnostic::Group(group) => Some(group),
15861            _ => None,
15862        }
15863    }
15864
15865    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15866        self.dismiss_diagnostics(cx);
15867        self.active_diagnostics = ActiveDiagnostic::All;
15868    }
15869
15870    fn activate_diagnostics(
15871        &mut self,
15872        buffer_id: BufferId,
15873        diagnostic: DiagnosticEntry<usize>,
15874        window: &mut Window,
15875        cx: &mut Context<Self>,
15876    ) {
15877        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15878            return;
15879        }
15880        self.dismiss_diagnostics(cx);
15881        let snapshot = self.snapshot(window, cx);
15882        let buffer = self.buffer.read(cx).snapshot(cx);
15883        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15884            return;
15885        };
15886
15887        let diagnostic_group = buffer
15888            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15889            .collect::<Vec<_>>();
15890
15891        let blocks =
15892            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15893
15894        let blocks = self.display_map.update(cx, |display_map, cx| {
15895            display_map.insert_blocks(blocks, cx).into_iter().collect()
15896        });
15897        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15898            active_range: buffer.anchor_before(diagnostic.range.start)
15899                ..buffer.anchor_after(diagnostic.range.end),
15900            active_message: diagnostic.diagnostic.message.clone(),
15901            group_id: diagnostic.diagnostic.group_id,
15902            blocks,
15903        });
15904        cx.notify();
15905    }
15906
15907    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15908        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15909            return;
15910        };
15911
15912        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15913        if let ActiveDiagnostic::Group(group) = prev {
15914            self.display_map.update(cx, |display_map, cx| {
15915                display_map.remove_blocks(group.blocks, cx);
15916            });
15917            cx.notify();
15918        }
15919    }
15920
15921    /// Disable inline diagnostics rendering for this editor.
15922    pub fn disable_inline_diagnostics(&mut self) {
15923        self.inline_diagnostics_enabled = false;
15924        self.inline_diagnostics_update = Task::ready(());
15925        self.inline_diagnostics.clear();
15926    }
15927
15928    pub fn diagnostics_enabled(&self) -> bool {
15929        self.mode.is_full()
15930    }
15931
15932    pub fn inline_diagnostics_enabled(&self) -> bool {
15933        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15934    }
15935
15936    pub fn show_inline_diagnostics(&self) -> bool {
15937        self.show_inline_diagnostics
15938    }
15939
15940    pub fn toggle_inline_diagnostics(
15941        &mut self,
15942        _: &ToggleInlineDiagnostics,
15943        window: &mut Window,
15944        cx: &mut Context<Editor>,
15945    ) {
15946        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15947        self.refresh_inline_diagnostics(false, window, cx);
15948    }
15949
15950    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15951        self.diagnostics_max_severity = severity;
15952        self.display_map.update(cx, |display_map, _| {
15953            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15954        });
15955    }
15956
15957    pub fn toggle_diagnostics(
15958        &mut self,
15959        _: &ToggleDiagnostics,
15960        window: &mut Window,
15961        cx: &mut Context<Editor>,
15962    ) {
15963        if !self.diagnostics_enabled() {
15964            return;
15965        }
15966
15967        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15968            EditorSettings::get_global(cx)
15969                .diagnostics_max_severity
15970                .filter(|severity| severity != &DiagnosticSeverity::Off)
15971                .unwrap_or(DiagnosticSeverity::Hint)
15972        } else {
15973            DiagnosticSeverity::Off
15974        };
15975        self.set_max_diagnostics_severity(new_severity, cx);
15976        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15977            self.active_diagnostics = ActiveDiagnostic::None;
15978            self.inline_diagnostics_update = Task::ready(());
15979            self.inline_diagnostics.clear();
15980        } else {
15981            self.refresh_inline_diagnostics(false, window, cx);
15982        }
15983
15984        cx.notify();
15985    }
15986
15987    pub fn toggle_minimap(
15988        &mut self,
15989        _: &ToggleMinimap,
15990        window: &mut Window,
15991        cx: &mut Context<Editor>,
15992    ) {
15993        if self.supports_minimap(cx) {
15994            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15995        }
15996    }
15997
15998    fn refresh_inline_diagnostics(
15999        &mut self,
16000        debounce: bool,
16001        window: &mut Window,
16002        cx: &mut Context<Self>,
16003    ) {
16004        let max_severity = ProjectSettings::get_global(cx)
16005            .diagnostics
16006            .inline
16007            .max_severity
16008            .unwrap_or(self.diagnostics_max_severity);
16009
16010        if !self.inline_diagnostics_enabled()
16011            || !self.show_inline_diagnostics
16012            || max_severity == DiagnosticSeverity::Off
16013        {
16014            self.inline_diagnostics_update = Task::ready(());
16015            self.inline_diagnostics.clear();
16016            return;
16017        }
16018
16019        let debounce_ms = ProjectSettings::get_global(cx)
16020            .diagnostics
16021            .inline
16022            .update_debounce_ms;
16023        let debounce = if debounce && debounce_ms > 0 {
16024            Some(Duration::from_millis(debounce_ms))
16025        } else {
16026            None
16027        };
16028        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16029            if let Some(debounce) = debounce {
16030                cx.background_executor().timer(debounce).await;
16031            }
16032            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16033                editor
16034                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16035                    .ok()
16036            }) else {
16037                return;
16038            };
16039
16040            let new_inline_diagnostics = cx
16041                .background_spawn(async move {
16042                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16043                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16044                        let message = diagnostic_entry
16045                            .diagnostic
16046                            .message
16047                            .split_once('\n')
16048                            .map(|(line, _)| line)
16049                            .map(SharedString::new)
16050                            .unwrap_or_else(|| {
16051                                SharedString::from(diagnostic_entry.diagnostic.message)
16052                            });
16053                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16054                        let (Ok(i) | Err(i)) = inline_diagnostics
16055                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16056                        inline_diagnostics.insert(
16057                            i,
16058                            (
16059                                start_anchor,
16060                                InlineDiagnostic {
16061                                    message,
16062                                    group_id: diagnostic_entry.diagnostic.group_id,
16063                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16064                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16065                                    severity: diagnostic_entry.diagnostic.severity,
16066                                },
16067                            ),
16068                        );
16069                    }
16070                    inline_diagnostics
16071                })
16072                .await;
16073
16074            editor
16075                .update(cx, |editor, cx| {
16076                    editor.inline_diagnostics = new_inline_diagnostics;
16077                    cx.notify();
16078                })
16079                .ok();
16080        });
16081    }
16082
16083    fn pull_diagnostics(
16084        &mut self,
16085        buffer_id: Option<BufferId>,
16086        window: &Window,
16087        cx: &mut Context<Self>,
16088    ) -> Option<()> {
16089        if !self.mode().is_full() {
16090            return None;
16091        }
16092        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16093            .diagnostics
16094            .lsp_pull_diagnostics;
16095        if !pull_diagnostics_settings.enabled {
16096            return None;
16097        }
16098        let project = self.project.as_ref()?.downgrade();
16099        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16100        let mut buffers = self.buffer.read(cx).all_buffers();
16101        if let Some(buffer_id) = buffer_id {
16102            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16103        }
16104
16105        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16106            cx.background_executor().timer(debounce).await;
16107
16108            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16109                buffers
16110                    .into_iter()
16111                    .flat_map(|buffer| {
16112                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16113                    })
16114                    .collect::<FuturesUnordered<_>>()
16115            }) else {
16116                return;
16117            };
16118
16119            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16120                match pull_task {
16121                    Ok(()) => {
16122                        if editor
16123                            .update_in(cx, |editor, window, cx| {
16124                                editor.update_diagnostics_state(window, cx);
16125                            })
16126                            .is_err()
16127                        {
16128                            return;
16129                        }
16130                    }
16131                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16132                }
16133            }
16134        });
16135
16136        Some(())
16137    }
16138
16139    pub fn set_selections_from_remote(
16140        &mut self,
16141        selections: Vec<Selection<Anchor>>,
16142        pending_selection: Option<Selection<Anchor>>,
16143        window: &mut Window,
16144        cx: &mut Context<Self>,
16145    ) {
16146        let old_cursor_position = self.selections.newest_anchor().head();
16147        self.selections.change_with(cx, |s| {
16148            s.select_anchors(selections);
16149            if let Some(pending_selection) = pending_selection {
16150                s.set_pending(pending_selection, SelectMode::Character);
16151            } else {
16152                s.clear_pending();
16153            }
16154        });
16155        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16156    }
16157
16158    pub fn transact(
16159        &mut self,
16160        window: &mut Window,
16161        cx: &mut Context<Self>,
16162        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16163    ) -> Option<TransactionId> {
16164        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16165            this.start_transaction_at(Instant::now(), window, cx);
16166            update(this, window, cx);
16167            this.end_transaction_at(Instant::now(), cx)
16168        })
16169    }
16170
16171    pub fn start_transaction_at(
16172        &mut self,
16173        now: Instant,
16174        window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) {
16177        self.end_selection(window, cx);
16178        if let Some(tx_id) = self
16179            .buffer
16180            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16181        {
16182            self.selection_history
16183                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16184            cx.emit(EditorEvent::TransactionBegun {
16185                transaction_id: tx_id,
16186            })
16187        }
16188    }
16189
16190    pub fn end_transaction_at(
16191        &mut self,
16192        now: Instant,
16193        cx: &mut Context<Self>,
16194    ) -> Option<TransactionId> {
16195        if let Some(transaction_id) = self
16196            .buffer
16197            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16198        {
16199            if let Some((_, end_selections)) =
16200                self.selection_history.transaction_mut(transaction_id)
16201            {
16202                *end_selections = Some(self.selections.disjoint_anchors());
16203            } else {
16204                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16205            }
16206
16207            cx.emit(EditorEvent::Edited { transaction_id });
16208            Some(transaction_id)
16209        } else {
16210            None
16211        }
16212    }
16213
16214    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16215        if self.selection_mark_mode {
16216            self.change_selections(None, window, cx, |s| {
16217                s.move_with(|_, sel| {
16218                    sel.collapse_to(sel.head(), SelectionGoal::None);
16219                });
16220            })
16221        }
16222        self.selection_mark_mode = true;
16223        cx.notify();
16224    }
16225
16226    pub fn swap_selection_ends(
16227        &mut self,
16228        _: &actions::SwapSelectionEnds,
16229        window: &mut Window,
16230        cx: &mut Context<Self>,
16231    ) {
16232        self.change_selections(None, window, cx, |s| {
16233            s.move_with(|_, sel| {
16234                if sel.start != sel.end {
16235                    sel.reversed = !sel.reversed
16236                }
16237            });
16238        });
16239        self.request_autoscroll(Autoscroll::newest(), cx);
16240        cx.notify();
16241    }
16242
16243    pub fn toggle_fold(
16244        &mut self,
16245        _: &actions::ToggleFold,
16246        window: &mut Window,
16247        cx: &mut Context<Self>,
16248    ) {
16249        if self.is_singleton(cx) {
16250            let selection = self.selections.newest::<Point>(cx);
16251
16252            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16253            let range = if selection.is_empty() {
16254                let point = selection.head().to_display_point(&display_map);
16255                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16256                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16257                    .to_point(&display_map);
16258                start..end
16259            } else {
16260                selection.range()
16261            };
16262            if display_map.folds_in_range(range).next().is_some() {
16263                self.unfold_lines(&Default::default(), window, cx)
16264            } else {
16265                self.fold(&Default::default(), window, cx)
16266            }
16267        } else {
16268            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16269            let buffer_ids: HashSet<_> = self
16270                .selections
16271                .disjoint_anchor_ranges()
16272                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16273                .collect();
16274
16275            let should_unfold = buffer_ids
16276                .iter()
16277                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16278
16279            for buffer_id in buffer_ids {
16280                if should_unfold {
16281                    self.unfold_buffer(buffer_id, cx);
16282                } else {
16283                    self.fold_buffer(buffer_id, cx);
16284                }
16285            }
16286        }
16287    }
16288
16289    pub fn toggle_fold_recursive(
16290        &mut self,
16291        _: &actions::ToggleFoldRecursive,
16292        window: &mut Window,
16293        cx: &mut Context<Self>,
16294    ) {
16295        let selection = self.selections.newest::<Point>(cx);
16296
16297        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16298        let range = if selection.is_empty() {
16299            let point = selection.head().to_display_point(&display_map);
16300            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16301            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16302                .to_point(&display_map);
16303            start..end
16304        } else {
16305            selection.range()
16306        };
16307        if display_map.folds_in_range(range).next().is_some() {
16308            self.unfold_recursive(&Default::default(), window, cx)
16309        } else {
16310            self.fold_recursive(&Default::default(), window, cx)
16311        }
16312    }
16313
16314    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16315        if self.is_singleton(cx) {
16316            let mut to_fold = Vec::new();
16317            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16318            let selections = self.selections.all_adjusted(cx);
16319
16320            for selection in selections {
16321                let range = selection.range().sorted();
16322                let buffer_start_row = range.start.row;
16323
16324                if range.start.row != range.end.row {
16325                    let mut found = false;
16326                    let mut row = range.start.row;
16327                    while row <= range.end.row {
16328                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16329                        {
16330                            found = true;
16331                            row = crease.range().end.row + 1;
16332                            to_fold.push(crease);
16333                        } else {
16334                            row += 1
16335                        }
16336                    }
16337                    if found {
16338                        continue;
16339                    }
16340                }
16341
16342                for row in (0..=range.start.row).rev() {
16343                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16344                        if crease.range().end.row >= buffer_start_row {
16345                            to_fold.push(crease);
16346                            if row <= range.start.row {
16347                                break;
16348                            }
16349                        }
16350                    }
16351                }
16352            }
16353
16354            self.fold_creases(to_fold, true, window, cx);
16355        } else {
16356            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16357            let buffer_ids = self
16358                .selections
16359                .disjoint_anchor_ranges()
16360                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16361                .collect::<HashSet<_>>();
16362            for buffer_id in buffer_ids {
16363                self.fold_buffer(buffer_id, cx);
16364            }
16365        }
16366    }
16367
16368    fn fold_at_level(
16369        &mut self,
16370        fold_at: &FoldAtLevel,
16371        window: &mut Window,
16372        cx: &mut Context<Self>,
16373    ) {
16374        if !self.buffer.read(cx).is_singleton() {
16375            return;
16376        }
16377
16378        let fold_at_level = fold_at.0;
16379        let snapshot = self.buffer.read(cx).snapshot(cx);
16380        let mut to_fold = Vec::new();
16381        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16382
16383        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16384            while start_row < end_row {
16385                match self
16386                    .snapshot(window, cx)
16387                    .crease_for_buffer_row(MultiBufferRow(start_row))
16388                {
16389                    Some(crease) => {
16390                        let nested_start_row = crease.range().start.row + 1;
16391                        let nested_end_row = crease.range().end.row;
16392
16393                        if current_level < fold_at_level {
16394                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16395                        } else if current_level == fold_at_level {
16396                            to_fold.push(crease);
16397                        }
16398
16399                        start_row = nested_end_row + 1;
16400                    }
16401                    None => start_row += 1,
16402                }
16403            }
16404        }
16405
16406        self.fold_creases(to_fold, true, window, cx);
16407    }
16408
16409    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16410        if self.buffer.read(cx).is_singleton() {
16411            let mut fold_ranges = Vec::new();
16412            let snapshot = self.buffer.read(cx).snapshot(cx);
16413
16414            for row in 0..snapshot.max_row().0 {
16415                if let Some(foldable_range) = self
16416                    .snapshot(window, cx)
16417                    .crease_for_buffer_row(MultiBufferRow(row))
16418                {
16419                    fold_ranges.push(foldable_range);
16420                }
16421            }
16422
16423            self.fold_creases(fold_ranges, true, window, cx);
16424        } else {
16425            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16426                editor
16427                    .update_in(cx, |editor, _, cx| {
16428                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16429                            editor.fold_buffer(buffer_id, cx);
16430                        }
16431                    })
16432                    .ok();
16433            });
16434        }
16435    }
16436
16437    pub fn fold_function_bodies(
16438        &mut self,
16439        _: &actions::FoldFunctionBodies,
16440        window: &mut Window,
16441        cx: &mut Context<Self>,
16442    ) {
16443        let snapshot = self.buffer.read(cx).snapshot(cx);
16444
16445        let ranges = snapshot
16446            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16447            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16448            .collect::<Vec<_>>();
16449
16450        let creases = ranges
16451            .into_iter()
16452            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16453            .collect();
16454
16455        self.fold_creases(creases, true, window, cx);
16456    }
16457
16458    pub fn fold_recursive(
16459        &mut self,
16460        _: &actions::FoldRecursive,
16461        window: &mut Window,
16462        cx: &mut Context<Self>,
16463    ) {
16464        let mut to_fold = Vec::new();
16465        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16466        let selections = self.selections.all_adjusted(cx);
16467
16468        for selection in selections {
16469            let range = selection.range().sorted();
16470            let buffer_start_row = range.start.row;
16471
16472            if range.start.row != range.end.row {
16473                let mut found = false;
16474                for row in range.start.row..=range.end.row {
16475                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16476                        found = true;
16477                        to_fold.push(crease);
16478                    }
16479                }
16480                if found {
16481                    continue;
16482                }
16483            }
16484
16485            for row in (0..=range.start.row).rev() {
16486                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16487                    if crease.range().end.row >= buffer_start_row {
16488                        to_fold.push(crease);
16489                    } else {
16490                        break;
16491                    }
16492                }
16493            }
16494        }
16495
16496        self.fold_creases(to_fold, true, window, cx);
16497    }
16498
16499    pub fn fold_at(
16500        &mut self,
16501        buffer_row: MultiBufferRow,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16506
16507        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16508            let autoscroll = self
16509                .selections
16510                .all::<Point>(cx)
16511                .iter()
16512                .any(|selection| crease.range().overlaps(&selection.range()));
16513
16514            self.fold_creases(vec![crease], autoscroll, window, cx);
16515        }
16516    }
16517
16518    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16519        if self.is_singleton(cx) {
16520            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16521            let buffer = &display_map.buffer_snapshot;
16522            let selections = self.selections.all::<Point>(cx);
16523            let ranges = selections
16524                .iter()
16525                .map(|s| {
16526                    let range = s.display_range(&display_map).sorted();
16527                    let mut start = range.start.to_point(&display_map);
16528                    let mut end = range.end.to_point(&display_map);
16529                    start.column = 0;
16530                    end.column = buffer.line_len(MultiBufferRow(end.row));
16531                    start..end
16532                })
16533                .collect::<Vec<_>>();
16534
16535            self.unfold_ranges(&ranges, true, true, cx);
16536        } else {
16537            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16538            let buffer_ids = self
16539                .selections
16540                .disjoint_anchor_ranges()
16541                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16542                .collect::<HashSet<_>>();
16543            for buffer_id in buffer_ids {
16544                self.unfold_buffer(buffer_id, cx);
16545            }
16546        }
16547    }
16548
16549    pub fn unfold_recursive(
16550        &mut self,
16551        _: &UnfoldRecursive,
16552        _window: &mut Window,
16553        cx: &mut Context<Self>,
16554    ) {
16555        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16556        let selections = self.selections.all::<Point>(cx);
16557        let ranges = selections
16558            .iter()
16559            .map(|s| {
16560                let mut range = s.display_range(&display_map).sorted();
16561                *range.start.column_mut() = 0;
16562                *range.end.column_mut() = display_map.line_len(range.end.row());
16563                let start = range.start.to_point(&display_map);
16564                let end = range.end.to_point(&display_map);
16565                start..end
16566            })
16567            .collect::<Vec<_>>();
16568
16569        self.unfold_ranges(&ranges, true, true, cx);
16570    }
16571
16572    pub fn unfold_at(
16573        &mut self,
16574        buffer_row: MultiBufferRow,
16575        _window: &mut Window,
16576        cx: &mut Context<Self>,
16577    ) {
16578        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16579
16580        let intersection_range = Point::new(buffer_row.0, 0)
16581            ..Point::new(
16582                buffer_row.0,
16583                display_map.buffer_snapshot.line_len(buffer_row),
16584            );
16585
16586        let autoscroll = self
16587            .selections
16588            .all::<Point>(cx)
16589            .iter()
16590            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16591
16592        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16593    }
16594
16595    pub fn unfold_all(
16596        &mut self,
16597        _: &actions::UnfoldAll,
16598        _window: &mut Window,
16599        cx: &mut Context<Self>,
16600    ) {
16601        if self.buffer.read(cx).is_singleton() {
16602            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16603            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16604        } else {
16605            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16606                editor
16607                    .update(cx, |editor, cx| {
16608                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16609                            editor.unfold_buffer(buffer_id, cx);
16610                        }
16611                    })
16612                    .ok();
16613            });
16614        }
16615    }
16616
16617    pub fn fold_selected_ranges(
16618        &mut self,
16619        _: &FoldSelectedRanges,
16620        window: &mut Window,
16621        cx: &mut Context<Self>,
16622    ) {
16623        let selections = self.selections.all_adjusted(cx);
16624        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16625        let ranges = selections
16626            .into_iter()
16627            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16628            .collect::<Vec<_>>();
16629        self.fold_creases(ranges, true, window, cx);
16630    }
16631
16632    pub fn fold_ranges<T: ToOffset + Clone>(
16633        &mut self,
16634        ranges: Vec<Range<T>>,
16635        auto_scroll: bool,
16636        window: &mut Window,
16637        cx: &mut Context<Self>,
16638    ) {
16639        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16640        let ranges = ranges
16641            .into_iter()
16642            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16643            .collect::<Vec<_>>();
16644        self.fold_creases(ranges, auto_scroll, window, cx);
16645    }
16646
16647    pub fn fold_creases<T: ToOffset + Clone>(
16648        &mut self,
16649        creases: Vec<Crease<T>>,
16650        auto_scroll: bool,
16651        _window: &mut Window,
16652        cx: &mut Context<Self>,
16653    ) {
16654        if creases.is_empty() {
16655            return;
16656        }
16657
16658        let mut buffers_affected = HashSet::default();
16659        let multi_buffer = self.buffer().read(cx);
16660        for crease in &creases {
16661            if let Some((_, buffer, _)) =
16662                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16663            {
16664                buffers_affected.insert(buffer.read(cx).remote_id());
16665            };
16666        }
16667
16668        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16669
16670        if auto_scroll {
16671            self.request_autoscroll(Autoscroll::fit(), cx);
16672        }
16673
16674        cx.notify();
16675
16676        self.scrollbar_marker_state.dirty = true;
16677        self.folds_did_change(cx);
16678    }
16679
16680    /// Removes any folds whose ranges intersect any of the given ranges.
16681    pub fn unfold_ranges<T: ToOffset + Clone>(
16682        &mut self,
16683        ranges: &[Range<T>],
16684        inclusive: bool,
16685        auto_scroll: bool,
16686        cx: &mut Context<Self>,
16687    ) {
16688        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16689            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16690        });
16691        self.folds_did_change(cx);
16692    }
16693
16694    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16695        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16696            return;
16697        }
16698        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16699        self.display_map.update(cx, |display_map, cx| {
16700            display_map.fold_buffers([buffer_id], cx)
16701        });
16702        cx.emit(EditorEvent::BufferFoldToggled {
16703            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16704            folded: true,
16705        });
16706        cx.notify();
16707    }
16708
16709    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16710        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16711            return;
16712        }
16713        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16714        self.display_map.update(cx, |display_map, cx| {
16715            display_map.unfold_buffers([buffer_id], cx);
16716        });
16717        cx.emit(EditorEvent::BufferFoldToggled {
16718            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16719            folded: false,
16720        });
16721        cx.notify();
16722    }
16723
16724    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16725        self.display_map.read(cx).is_buffer_folded(buffer)
16726    }
16727
16728    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16729        self.display_map.read(cx).folded_buffers()
16730    }
16731
16732    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16733        self.display_map.update(cx, |display_map, cx| {
16734            display_map.disable_header_for_buffer(buffer_id, cx);
16735        });
16736        cx.notify();
16737    }
16738
16739    /// Removes any folds with the given ranges.
16740    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16741        &mut self,
16742        ranges: &[Range<T>],
16743        type_id: TypeId,
16744        auto_scroll: bool,
16745        cx: &mut Context<Self>,
16746    ) {
16747        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16748            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16749        });
16750        self.folds_did_change(cx);
16751    }
16752
16753    fn remove_folds_with<T: ToOffset + Clone>(
16754        &mut self,
16755        ranges: &[Range<T>],
16756        auto_scroll: bool,
16757        cx: &mut Context<Self>,
16758        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16759    ) {
16760        if ranges.is_empty() {
16761            return;
16762        }
16763
16764        let mut buffers_affected = HashSet::default();
16765        let multi_buffer = self.buffer().read(cx);
16766        for range in ranges {
16767            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16768                buffers_affected.insert(buffer.read(cx).remote_id());
16769            };
16770        }
16771
16772        self.display_map.update(cx, update);
16773
16774        if auto_scroll {
16775            self.request_autoscroll(Autoscroll::fit(), cx);
16776        }
16777
16778        cx.notify();
16779        self.scrollbar_marker_state.dirty = true;
16780        self.active_indent_guides_state.dirty = true;
16781    }
16782
16783    pub fn update_fold_widths(
16784        &mut self,
16785        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16786        cx: &mut Context<Self>,
16787    ) -> bool {
16788        self.display_map
16789            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16790    }
16791
16792    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16793        self.display_map.read(cx).fold_placeholder.clone()
16794    }
16795
16796    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16797        self.buffer.update(cx, |buffer, cx| {
16798            buffer.set_all_diff_hunks_expanded(cx);
16799        });
16800    }
16801
16802    pub fn expand_all_diff_hunks(
16803        &mut self,
16804        _: &ExpandAllDiffHunks,
16805        _window: &mut Window,
16806        cx: &mut Context<Self>,
16807    ) {
16808        self.buffer.update(cx, |buffer, cx| {
16809            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16810        });
16811    }
16812
16813    pub fn toggle_selected_diff_hunks(
16814        &mut self,
16815        _: &ToggleSelectedDiffHunks,
16816        _window: &mut Window,
16817        cx: &mut Context<Self>,
16818    ) {
16819        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16820        self.toggle_diff_hunks_in_ranges(ranges, cx);
16821    }
16822
16823    pub fn diff_hunks_in_ranges<'a>(
16824        &'a self,
16825        ranges: &'a [Range<Anchor>],
16826        buffer: &'a MultiBufferSnapshot,
16827    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16828        ranges.iter().flat_map(move |range| {
16829            let end_excerpt_id = range.end.excerpt_id;
16830            let range = range.to_point(buffer);
16831            let mut peek_end = range.end;
16832            if range.end.row < buffer.max_row().0 {
16833                peek_end = Point::new(range.end.row + 1, 0);
16834            }
16835            buffer
16836                .diff_hunks_in_range(range.start..peek_end)
16837                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16838        })
16839    }
16840
16841    pub fn has_stageable_diff_hunks_in_ranges(
16842        &self,
16843        ranges: &[Range<Anchor>],
16844        snapshot: &MultiBufferSnapshot,
16845    ) -> bool {
16846        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16847        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16848    }
16849
16850    pub fn toggle_staged_selected_diff_hunks(
16851        &mut self,
16852        _: &::git::ToggleStaged,
16853        _: &mut Window,
16854        cx: &mut Context<Self>,
16855    ) {
16856        let snapshot = self.buffer.read(cx).snapshot(cx);
16857        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16858        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16859        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16860    }
16861
16862    pub fn set_render_diff_hunk_controls(
16863        &mut self,
16864        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16865        cx: &mut Context<Self>,
16866    ) {
16867        self.render_diff_hunk_controls = render_diff_hunk_controls;
16868        cx.notify();
16869    }
16870
16871    pub fn stage_and_next(
16872        &mut self,
16873        _: &::git::StageAndNext,
16874        window: &mut Window,
16875        cx: &mut Context<Self>,
16876    ) {
16877        self.do_stage_or_unstage_and_next(true, window, cx);
16878    }
16879
16880    pub fn unstage_and_next(
16881        &mut self,
16882        _: &::git::UnstageAndNext,
16883        window: &mut Window,
16884        cx: &mut Context<Self>,
16885    ) {
16886        self.do_stage_or_unstage_and_next(false, window, cx);
16887    }
16888
16889    pub fn stage_or_unstage_diff_hunks(
16890        &mut self,
16891        stage: bool,
16892        ranges: Vec<Range<Anchor>>,
16893        cx: &mut Context<Self>,
16894    ) {
16895        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16896        cx.spawn(async move |this, cx| {
16897            task.await?;
16898            this.update(cx, |this, cx| {
16899                let snapshot = this.buffer.read(cx).snapshot(cx);
16900                let chunk_by = this
16901                    .diff_hunks_in_ranges(&ranges, &snapshot)
16902                    .chunk_by(|hunk| hunk.buffer_id);
16903                for (buffer_id, hunks) in &chunk_by {
16904                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16905                }
16906            })
16907        })
16908        .detach_and_log_err(cx);
16909    }
16910
16911    fn save_buffers_for_ranges_if_needed(
16912        &mut self,
16913        ranges: &[Range<Anchor>],
16914        cx: &mut Context<Editor>,
16915    ) -> Task<Result<()>> {
16916        let multibuffer = self.buffer.read(cx);
16917        let snapshot = multibuffer.read(cx);
16918        let buffer_ids: HashSet<_> = ranges
16919            .iter()
16920            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16921            .collect();
16922        drop(snapshot);
16923
16924        let mut buffers = HashSet::default();
16925        for buffer_id in buffer_ids {
16926            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16927                let buffer = buffer_entity.read(cx);
16928                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16929                {
16930                    buffers.insert(buffer_entity);
16931                }
16932            }
16933        }
16934
16935        if let Some(project) = &self.project {
16936            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16937        } else {
16938            Task::ready(Ok(()))
16939        }
16940    }
16941
16942    fn do_stage_or_unstage_and_next(
16943        &mut self,
16944        stage: bool,
16945        window: &mut Window,
16946        cx: &mut Context<Self>,
16947    ) {
16948        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16949
16950        if ranges.iter().any(|range| range.start != range.end) {
16951            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16952            return;
16953        }
16954
16955        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16956        let snapshot = self.snapshot(window, cx);
16957        let position = self.selections.newest::<Point>(cx).head();
16958        let mut row = snapshot
16959            .buffer_snapshot
16960            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16961            .find(|hunk| hunk.row_range.start.0 > position.row)
16962            .map(|hunk| hunk.row_range.start);
16963
16964        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16965        // Outside of the project diff editor, wrap around to the beginning.
16966        if !all_diff_hunks_expanded {
16967            row = row.or_else(|| {
16968                snapshot
16969                    .buffer_snapshot
16970                    .diff_hunks_in_range(Point::zero()..position)
16971                    .find(|hunk| hunk.row_range.end.0 < position.row)
16972                    .map(|hunk| hunk.row_range.start)
16973            });
16974        }
16975
16976        if let Some(row) = row {
16977            let destination = Point::new(row.0, 0);
16978            let autoscroll = Autoscroll::center();
16979
16980            self.unfold_ranges(&[destination..destination], false, false, cx);
16981            self.change_selections(Some(autoscroll), window, cx, |s| {
16982                s.select_ranges([destination..destination]);
16983            });
16984        }
16985    }
16986
16987    fn do_stage_or_unstage(
16988        &self,
16989        stage: bool,
16990        buffer_id: BufferId,
16991        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16992        cx: &mut App,
16993    ) -> Option<()> {
16994        let project = self.project.as_ref()?;
16995        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16996        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16997        let buffer_snapshot = buffer.read(cx).snapshot();
16998        let file_exists = buffer_snapshot
16999            .file()
17000            .is_some_and(|file| file.disk_state().exists());
17001        diff.update(cx, |diff, cx| {
17002            diff.stage_or_unstage_hunks(
17003                stage,
17004                &hunks
17005                    .map(|hunk| buffer_diff::DiffHunk {
17006                        buffer_range: hunk.buffer_range,
17007                        diff_base_byte_range: hunk.diff_base_byte_range,
17008                        secondary_status: hunk.secondary_status,
17009                        range: Point::zero()..Point::zero(), // unused
17010                    })
17011                    .collect::<Vec<_>>(),
17012                &buffer_snapshot,
17013                file_exists,
17014                cx,
17015            )
17016        });
17017        None
17018    }
17019
17020    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17021        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17022        self.buffer
17023            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17024    }
17025
17026    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17027        self.buffer.update(cx, |buffer, cx| {
17028            let ranges = vec![Anchor::min()..Anchor::max()];
17029            if !buffer.all_diff_hunks_expanded()
17030                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17031            {
17032                buffer.collapse_diff_hunks(ranges, cx);
17033                true
17034            } else {
17035                false
17036            }
17037        })
17038    }
17039
17040    fn toggle_diff_hunks_in_ranges(
17041        &mut self,
17042        ranges: Vec<Range<Anchor>>,
17043        cx: &mut Context<Editor>,
17044    ) {
17045        self.buffer.update(cx, |buffer, cx| {
17046            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17047            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17048        })
17049    }
17050
17051    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17052        self.buffer.update(cx, |buffer, cx| {
17053            let snapshot = buffer.snapshot(cx);
17054            let excerpt_id = range.end.excerpt_id;
17055            let point_range = range.to_point(&snapshot);
17056            let expand = !buffer.single_hunk_is_expanded(range, cx);
17057            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17058        })
17059    }
17060
17061    pub(crate) fn apply_all_diff_hunks(
17062        &mut self,
17063        _: &ApplyAllDiffHunks,
17064        window: &mut Window,
17065        cx: &mut Context<Self>,
17066    ) {
17067        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17068
17069        let buffers = self.buffer.read(cx).all_buffers();
17070        for branch_buffer in buffers {
17071            branch_buffer.update(cx, |branch_buffer, cx| {
17072                branch_buffer.merge_into_base(Vec::new(), cx);
17073            });
17074        }
17075
17076        if let Some(project) = self.project.clone() {
17077            self.save(true, project, window, cx).detach_and_log_err(cx);
17078        }
17079    }
17080
17081    pub(crate) fn apply_selected_diff_hunks(
17082        &mut self,
17083        _: &ApplyDiffHunk,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) {
17087        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17088        let snapshot = self.snapshot(window, cx);
17089        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17090        let mut ranges_by_buffer = HashMap::default();
17091        self.transact(window, cx, |editor, _window, cx| {
17092            for hunk in hunks {
17093                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17094                    ranges_by_buffer
17095                        .entry(buffer.clone())
17096                        .or_insert_with(Vec::new)
17097                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17098                }
17099            }
17100
17101            for (buffer, ranges) in ranges_by_buffer {
17102                buffer.update(cx, |buffer, cx| {
17103                    buffer.merge_into_base(ranges, cx);
17104                });
17105            }
17106        });
17107
17108        if let Some(project) = self.project.clone() {
17109            self.save(true, project, window, cx).detach_and_log_err(cx);
17110        }
17111    }
17112
17113    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17114        if hovered != self.gutter_hovered {
17115            self.gutter_hovered = hovered;
17116            cx.notify();
17117        }
17118    }
17119
17120    pub fn insert_blocks(
17121        &mut self,
17122        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17123        autoscroll: Option<Autoscroll>,
17124        cx: &mut Context<Self>,
17125    ) -> Vec<CustomBlockId> {
17126        let blocks = self
17127            .display_map
17128            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17129        if let Some(autoscroll) = autoscroll {
17130            self.request_autoscroll(autoscroll, cx);
17131        }
17132        cx.notify();
17133        blocks
17134    }
17135
17136    pub fn resize_blocks(
17137        &mut self,
17138        heights: HashMap<CustomBlockId, u32>,
17139        autoscroll: Option<Autoscroll>,
17140        cx: &mut Context<Self>,
17141    ) {
17142        self.display_map
17143            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17144        if let Some(autoscroll) = autoscroll {
17145            self.request_autoscroll(autoscroll, cx);
17146        }
17147        cx.notify();
17148    }
17149
17150    pub fn replace_blocks(
17151        &mut self,
17152        renderers: HashMap<CustomBlockId, RenderBlock>,
17153        autoscroll: Option<Autoscroll>,
17154        cx: &mut Context<Self>,
17155    ) {
17156        self.display_map
17157            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17158        if let Some(autoscroll) = autoscroll {
17159            self.request_autoscroll(autoscroll, cx);
17160        }
17161        cx.notify();
17162    }
17163
17164    pub fn remove_blocks(
17165        &mut self,
17166        block_ids: HashSet<CustomBlockId>,
17167        autoscroll: Option<Autoscroll>,
17168        cx: &mut Context<Self>,
17169    ) {
17170        self.display_map.update(cx, |display_map, cx| {
17171            display_map.remove_blocks(block_ids, cx)
17172        });
17173        if let Some(autoscroll) = autoscroll {
17174            self.request_autoscroll(autoscroll, cx);
17175        }
17176        cx.notify();
17177    }
17178
17179    pub fn row_for_block(
17180        &self,
17181        block_id: CustomBlockId,
17182        cx: &mut Context<Self>,
17183    ) -> Option<DisplayRow> {
17184        self.display_map
17185            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17186    }
17187
17188    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17189        self.focused_block = Some(focused_block);
17190    }
17191
17192    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17193        self.focused_block.take()
17194    }
17195
17196    pub fn insert_creases(
17197        &mut self,
17198        creases: impl IntoIterator<Item = Crease<Anchor>>,
17199        cx: &mut Context<Self>,
17200    ) -> Vec<CreaseId> {
17201        self.display_map
17202            .update(cx, |map, cx| map.insert_creases(creases, cx))
17203    }
17204
17205    pub fn remove_creases(
17206        &mut self,
17207        ids: impl IntoIterator<Item = CreaseId>,
17208        cx: &mut Context<Self>,
17209    ) -> Vec<(CreaseId, Range<Anchor>)> {
17210        self.display_map
17211            .update(cx, |map, cx| map.remove_creases(ids, cx))
17212    }
17213
17214    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17215        self.display_map
17216            .update(cx, |map, cx| map.snapshot(cx))
17217            .longest_row()
17218    }
17219
17220    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17221        self.display_map
17222            .update(cx, |map, cx| map.snapshot(cx))
17223            .max_point()
17224    }
17225
17226    pub fn text(&self, cx: &App) -> String {
17227        self.buffer.read(cx).read(cx).text()
17228    }
17229
17230    pub fn is_empty(&self, cx: &App) -> bool {
17231        self.buffer.read(cx).read(cx).is_empty()
17232    }
17233
17234    pub fn text_option(&self, cx: &App) -> Option<String> {
17235        let text = self.text(cx);
17236        let text = text.trim();
17237
17238        if text.is_empty() {
17239            return None;
17240        }
17241
17242        Some(text.to_string())
17243    }
17244
17245    pub fn set_text(
17246        &mut self,
17247        text: impl Into<Arc<str>>,
17248        window: &mut Window,
17249        cx: &mut Context<Self>,
17250    ) {
17251        self.transact(window, cx, |this, _, cx| {
17252            this.buffer
17253                .read(cx)
17254                .as_singleton()
17255                .expect("you can only call set_text on editors for singleton buffers")
17256                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17257        });
17258    }
17259
17260    pub fn display_text(&self, cx: &mut App) -> String {
17261        self.display_map
17262            .update(cx, |map, cx| map.snapshot(cx))
17263            .text()
17264    }
17265
17266    fn create_minimap(
17267        &self,
17268        minimap_settings: MinimapSettings,
17269        window: &mut Window,
17270        cx: &mut Context<Self>,
17271    ) -> Option<Entity<Self>> {
17272        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17273            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17274    }
17275
17276    fn initialize_new_minimap(
17277        &self,
17278        minimap_settings: MinimapSettings,
17279        window: &mut Window,
17280        cx: &mut Context<Self>,
17281    ) -> Entity<Self> {
17282        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17283
17284        let mut minimap = Editor::new_internal(
17285            EditorMode::Minimap {
17286                parent: cx.weak_entity(),
17287            },
17288            self.buffer.clone(),
17289            self.project.clone(),
17290            Some(self.display_map.clone()),
17291            window,
17292            cx,
17293        );
17294        minimap.scroll_manager.clone_state(&self.scroll_manager);
17295        minimap.set_text_style_refinement(TextStyleRefinement {
17296            font_size: Some(MINIMAP_FONT_SIZE),
17297            font_weight: Some(MINIMAP_FONT_WEIGHT),
17298            ..Default::default()
17299        });
17300        minimap.update_minimap_configuration(minimap_settings, cx);
17301        cx.new(|_| minimap)
17302    }
17303
17304    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17305        let current_line_highlight = minimap_settings
17306            .current_line_highlight
17307            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17308        self.set_current_line_highlight(Some(current_line_highlight));
17309    }
17310
17311    pub fn minimap(&self) -> Option<&Entity<Self>> {
17312        self.minimap
17313            .as_ref()
17314            .filter(|_| self.minimap_visibility.visible())
17315    }
17316
17317    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17318        let mut wrap_guides = smallvec![];
17319
17320        if self.show_wrap_guides == Some(false) {
17321            return wrap_guides;
17322        }
17323
17324        let settings = self.buffer.read(cx).language_settings(cx);
17325        if settings.show_wrap_guides {
17326            match self.soft_wrap_mode(cx) {
17327                SoftWrap::Column(soft_wrap) => {
17328                    wrap_guides.push((soft_wrap as usize, true));
17329                }
17330                SoftWrap::Bounded(soft_wrap) => {
17331                    wrap_guides.push((soft_wrap as usize, true));
17332                }
17333                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17334            }
17335            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17336        }
17337
17338        wrap_guides
17339    }
17340
17341    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17342        let settings = self.buffer.read(cx).language_settings(cx);
17343        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17344        match mode {
17345            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17346                SoftWrap::None
17347            }
17348            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17349            language_settings::SoftWrap::PreferredLineLength => {
17350                SoftWrap::Column(settings.preferred_line_length)
17351            }
17352            language_settings::SoftWrap::Bounded => {
17353                SoftWrap::Bounded(settings.preferred_line_length)
17354            }
17355        }
17356    }
17357
17358    pub fn set_soft_wrap_mode(
17359        &mut self,
17360        mode: language_settings::SoftWrap,
17361
17362        cx: &mut Context<Self>,
17363    ) {
17364        self.soft_wrap_mode_override = Some(mode);
17365        cx.notify();
17366    }
17367
17368    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17369        self.hard_wrap = hard_wrap;
17370        cx.notify();
17371    }
17372
17373    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17374        self.text_style_refinement = Some(style);
17375    }
17376
17377    /// called by the Element so we know what style we were most recently rendered with.
17378    pub(crate) fn set_style(
17379        &mut self,
17380        style: EditorStyle,
17381        window: &mut Window,
17382        cx: &mut Context<Self>,
17383    ) {
17384        // We intentionally do not inform the display map about the minimap style
17385        // so that wrapping is not recalculated and stays consistent for the editor
17386        // and its linked minimap.
17387        if !self.mode.is_minimap() {
17388            let rem_size = window.rem_size();
17389            self.display_map.update(cx, |map, cx| {
17390                map.set_font(
17391                    style.text.font(),
17392                    style.text.font_size.to_pixels(rem_size),
17393                    cx,
17394                )
17395            });
17396        }
17397        self.style = Some(style);
17398    }
17399
17400    pub fn style(&self) -> Option<&EditorStyle> {
17401        self.style.as_ref()
17402    }
17403
17404    // Called by the element. This method is not designed to be called outside of the editor
17405    // element's layout code because it does not notify when rewrapping is computed synchronously.
17406    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17407        self.display_map
17408            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17409    }
17410
17411    pub fn set_soft_wrap(&mut self) {
17412        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17413    }
17414
17415    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17416        if self.soft_wrap_mode_override.is_some() {
17417            self.soft_wrap_mode_override.take();
17418        } else {
17419            let soft_wrap = match self.soft_wrap_mode(cx) {
17420                SoftWrap::GitDiff => return,
17421                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17422                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17423                    language_settings::SoftWrap::None
17424                }
17425            };
17426            self.soft_wrap_mode_override = Some(soft_wrap);
17427        }
17428        cx.notify();
17429    }
17430
17431    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17432        let Some(workspace) = self.workspace() else {
17433            return;
17434        };
17435        let fs = workspace.read(cx).app_state().fs.clone();
17436        let current_show = TabBarSettings::get_global(cx).show;
17437        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17438            setting.show = Some(!current_show);
17439        });
17440    }
17441
17442    pub fn toggle_indent_guides(
17443        &mut self,
17444        _: &ToggleIndentGuides,
17445        _: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) {
17448        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17449            self.buffer
17450                .read(cx)
17451                .language_settings(cx)
17452                .indent_guides
17453                .enabled
17454        });
17455        self.show_indent_guides = Some(!currently_enabled);
17456        cx.notify();
17457    }
17458
17459    fn should_show_indent_guides(&self) -> Option<bool> {
17460        self.show_indent_guides
17461    }
17462
17463    pub fn toggle_line_numbers(
17464        &mut self,
17465        _: &ToggleLineNumbers,
17466        _: &mut Window,
17467        cx: &mut Context<Self>,
17468    ) {
17469        let mut editor_settings = EditorSettings::get_global(cx).clone();
17470        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17471        EditorSettings::override_global(editor_settings, cx);
17472    }
17473
17474    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17475        if let Some(show_line_numbers) = self.show_line_numbers {
17476            return show_line_numbers;
17477        }
17478        EditorSettings::get_global(cx).gutter.line_numbers
17479    }
17480
17481    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17482        self.use_relative_line_numbers
17483            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17484    }
17485
17486    pub fn toggle_relative_line_numbers(
17487        &mut self,
17488        _: &ToggleRelativeLineNumbers,
17489        _: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) {
17492        let is_relative = self.should_use_relative_line_numbers(cx);
17493        self.set_relative_line_number(Some(!is_relative), cx)
17494    }
17495
17496    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17497        self.use_relative_line_numbers = is_relative;
17498        cx.notify();
17499    }
17500
17501    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17502        self.show_gutter = show_gutter;
17503        cx.notify();
17504    }
17505
17506    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17507        self.show_scrollbars = ScrollbarAxes {
17508            horizontal: show,
17509            vertical: show,
17510        };
17511        cx.notify();
17512    }
17513
17514    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17515        self.show_scrollbars.vertical = show;
17516        cx.notify();
17517    }
17518
17519    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17520        self.show_scrollbars.horizontal = show;
17521        cx.notify();
17522    }
17523
17524    pub fn set_minimap_visibility(
17525        &mut self,
17526        minimap_visibility: MinimapVisibility,
17527        window: &mut Window,
17528        cx: &mut Context<Self>,
17529    ) {
17530        if self.minimap_visibility != minimap_visibility {
17531            if minimap_visibility.visible() && self.minimap.is_none() {
17532                let minimap_settings = EditorSettings::get_global(cx).minimap;
17533                self.minimap =
17534                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17535            }
17536            self.minimap_visibility = minimap_visibility;
17537            cx.notify();
17538        }
17539    }
17540
17541    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17542        self.set_show_scrollbars(false, cx);
17543        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17544    }
17545
17546    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17547        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17548    }
17549
17550    /// Normally the text in full mode and auto height editors is padded on the
17551    /// left side by roughly half a character width for improved hit testing.
17552    ///
17553    /// Use this method to disable this for cases where this is not wanted (e.g.
17554    /// if you want to align the editor text with some other text above or below)
17555    /// or if you want to add this padding to single-line editors.
17556    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17557        self.offset_content = offset_content;
17558        cx.notify();
17559    }
17560
17561    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17562        self.show_line_numbers = Some(show_line_numbers);
17563        cx.notify();
17564    }
17565
17566    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17567        self.disable_expand_excerpt_buttons = true;
17568        cx.notify();
17569    }
17570
17571    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17572        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17573        cx.notify();
17574    }
17575
17576    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17577        self.show_code_actions = Some(show_code_actions);
17578        cx.notify();
17579    }
17580
17581    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17582        self.show_runnables = Some(show_runnables);
17583        cx.notify();
17584    }
17585
17586    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17587        self.show_breakpoints = Some(show_breakpoints);
17588        cx.notify();
17589    }
17590
17591    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17592        if self.display_map.read(cx).masked != masked {
17593            self.display_map.update(cx, |map, _| map.masked = masked);
17594        }
17595        cx.notify()
17596    }
17597
17598    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17599        self.show_wrap_guides = Some(show_wrap_guides);
17600        cx.notify();
17601    }
17602
17603    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17604        self.show_indent_guides = Some(show_indent_guides);
17605        cx.notify();
17606    }
17607
17608    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17609        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17610            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17611                if let Some(dir) = file.abs_path(cx).parent() {
17612                    return Some(dir.to_owned());
17613                }
17614            }
17615
17616            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17617                return Some(project_path.path.to_path_buf());
17618            }
17619        }
17620
17621        None
17622    }
17623
17624    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17625        self.active_excerpt(cx)?
17626            .1
17627            .read(cx)
17628            .file()
17629            .and_then(|f| f.as_local())
17630    }
17631
17632    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17633        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17634            let buffer = buffer.read(cx);
17635            if let Some(project_path) = buffer.project_path(cx) {
17636                let project = self.project.as_ref()?.read(cx);
17637                project.absolute_path(&project_path, cx)
17638            } else {
17639                buffer
17640                    .file()
17641                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17642            }
17643        })
17644    }
17645
17646    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17647        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17648            let project_path = buffer.read(cx).project_path(cx)?;
17649            let project = self.project.as_ref()?.read(cx);
17650            let entry = project.entry_for_path(&project_path, cx)?;
17651            let path = entry.path.to_path_buf();
17652            Some(path)
17653        })
17654    }
17655
17656    pub fn reveal_in_finder(
17657        &mut self,
17658        _: &RevealInFileManager,
17659        _window: &mut Window,
17660        cx: &mut Context<Self>,
17661    ) {
17662        if let Some(target) = self.target_file(cx) {
17663            cx.reveal_path(&target.abs_path(cx));
17664        }
17665    }
17666
17667    pub fn copy_path(
17668        &mut self,
17669        _: &zed_actions::workspace::CopyPath,
17670        _window: &mut Window,
17671        cx: &mut Context<Self>,
17672    ) {
17673        if let Some(path) = self.target_file_abs_path(cx) {
17674            if let Some(path) = path.to_str() {
17675                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17676            }
17677        }
17678    }
17679
17680    pub fn copy_relative_path(
17681        &mut self,
17682        _: &zed_actions::workspace::CopyRelativePath,
17683        _window: &mut Window,
17684        cx: &mut Context<Self>,
17685    ) {
17686        if let Some(path) = self.target_file_path(cx) {
17687            if let Some(path) = path.to_str() {
17688                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17689            }
17690        }
17691    }
17692
17693    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17694        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17695            buffer.read(cx).project_path(cx)
17696        } else {
17697            None
17698        }
17699    }
17700
17701    // Returns true if the editor handled a go-to-line request
17702    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17703        maybe!({
17704            let breakpoint_store = self.breakpoint_store.as_ref()?;
17705
17706            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17707            else {
17708                self.clear_row_highlights::<ActiveDebugLine>();
17709                return None;
17710            };
17711
17712            let position = active_stack_frame.position;
17713            let buffer_id = position.buffer_id?;
17714            let snapshot = self
17715                .project
17716                .as_ref()?
17717                .read(cx)
17718                .buffer_for_id(buffer_id, cx)?
17719                .read(cx)
17720                .snapshot();
17721
17722            let mut handled = false;
17723            for (id, ExcerptRange { context, .. }) in
17724                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17725            {
17726                if context.start.cmp(&position, &snapshot).is_ge()
17727                    || context.end.cmp(&position, &snapshot).is_lt()
17728                {
17729                    continue;
17730                }
17731                let snapshot = self.buffer.read(cx).snapshot(cx);
17732                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17733
17734                handled = true;
17735                self.clear_row_highlights::<ActiveDebugLine>();
17736
17737                self.go_to_line::<ActiveDebugLine>(
17738                    multibuffer_anchor,
17739                    Some(cx.theme().colors().editor_debugger_active_line_background),
17740                    window,
17741                    cx,
17742                );
17743
17744                cx.notify();
17745            }
17746
17747            handled.then_some(())
17748        })
17749        .is_some()
17750    }
17751
17752    pub fn copy_file_name_without_extension(
17753        &mut self,
17754        _: &CopyFileNameWithoutExtension,
17755        _: &mut Window,
17756        cx: &mut Context<Self>,
17757    ) {
17758        if let Some(file) = self.target_file(cx) {
17759            if let Some(file_stem) = file.path().file_stem() {
17760                if let Some(name) = file_stem.to_str() {
17761                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17762                }
17763            }
17764        }
17765    }
17766
17767    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17768        if let Some(file) = self.target_file(cx) {
17769            if let Some(file_name) = file.path().file_name() {
17770                if let Some(name) = file_name.to_str() {
17771                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17772                }
17773            }
17774        }
17775    }
17776
17777    pub fn toggle_git_blame(
17778        &mut self,
17779        _: &::git::Blame,
17780        window: &mut Window,
17781        cx: &mut Context<Self>,
17782    ) {
17783        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17784
17785        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17786            self.start_git_blame(true, window, cx);
17787        }
17788
17789        cx.notify();
17790    }
17791
17792    pub fn toggle_git_blame_inline(
17793        &mut self,
17794        _: &ToggleGitBlameInline,
17795        window: &mut Window,
17796        cx: &mut Context<Self>,
17797    ) {
17798        self.toggle_git_blame_inline_internal(true, window, cx);
17799        cx.notify();
17800    }
17801
17802    pub fn open_git_blame_commit(
17803        &mut self,
17804        _: &OpenGitBlameCommit,
17805        window: &mut Window,
17806        cx: &mut Context<Self>,
17807    ) {
17808        self.open_git_blame_commit_internal(window, cx);
17809    }
17810
17811    fn open_git_blame_commit_internal(
17812        &mut self,
17813        window: &mut Window,
17814        cx: &mut Context<Self>,
17815    ) -> Option<()> {
17816        let blame = self.blame.as_ref()?;
17817        let snapshot = self.snapshot(window, cx);
17818        let cursor = self.selections.newest::<Point>(cx).head();
17819        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17820        let blame_entry = blame
17821            .update(cx, |blame, cx| {
17822                blame
17823                    .blame_for_rows(
17824                        &[RowInfo {
17825                            buffer_id: Some(buffer.remote_id()),
17826                            buffer_row: Some(point.row),
17827                            ..Default::default()
17828                        }],
17829                        cx,
17830                    )
17831                    .next()
17832            })
17833            .flatten()?;
17834        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17835        let repo = blame.read(cx).repository(cx)?;
17836        let workspace = self.workspace()?.downgrade();
17837        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17838        None
17839    }
17840
17841    pub fn git_blame_inline_enabled(&self) -> bool {
17842        self.git_blame_inline_enabled
17843    }
17844
17845    pub fn toggle_selection_menu(
17846        &mut self,
17847        _: &ToggleSelectionMenu,
17848        _: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) {
17851        self.show_selection_menu = self
17852            .show_selection_menu
17853            .map(|show_selections_menu| !show_selections_menu)
17854            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17855
17856        cx.notify();
17857    }
17858
17859    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17860        self.show_selection_menu
17861            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17862    }
17863
17864    fn start_git_blame(
17865        &mut self,
17866        user_triggered: bool,
17867        window: &mut Window,
17868        cx: &mut Context<Self>,
17869    ) {
17870        if let Some(project) = self.project.as_ref() {
17871            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17872                return;
17873            };
17874
17875            if buffer.read(cx).file().is_none() {
17876                return;
17877            }
17878
17879            let focused = self.focus_handle(cx).contains_focused(window, cx);
17880
17881            let project = project.clone();
17882            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17883            self.blame_subscription =
17884                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17885            self.blame = Some(blame);
17886        }
17887    }
17888
17889    fn toggle_git_blame_inline_internal(
17890        &mut self,
17891        user_triggered: bool,
17892        window: &mut Window,
17893        cx: &mut Context<Self>,
17894    ) {
17895        if self.git_blame_inline_enabled {
17896            self.git_blame_inline_enabled = false;
17897            self.show_git_blame_inline = false;
17898            self.show_git_blame_inline_delay_task.take();
17899        } else {
17900            self.git_blame_inline_enabled = true;
17901            self.start_git_blame_inline(user_triggered, window, cx);
17902        }
17903
17904        cx.notify();
17905    }
17906
17907    fn start_git_blame_inline(
17908        &mut self,
17909        user_triggered: bool,
17910        window: &mut Window,
17911        cx: &mut Context<Self>,
17912    ) {
17913        self.start_git_blame(user_triggered, window, cx);
17914
17915        if ProjectSettings::get_global(cx)
17916            .git
17917            .inline_blame_delay()
17918            .is_some()
17919        {
17920            self.start_inline_blame_timer(window, cx);
17921        } else {
17922            self.show_git_blame_inline = true
17923        }
17924    }
17925
17926    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17927        self.blame.as_ref()
17928    }
17929
17930    pub fn show_git_blame_gutter(&self) -> bool {
17931        self.show_git_blame_gutter
17932    }
17933
17934    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17935        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17936    }
17937
17938    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17939        self.show_git_blame_inline
17940            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17941            && !self.newest_selection_head_on_empty_line(cx)
17942            && self.has_blame_entries(cx)
17943    }
17944
17945    fn has_blame_entries(&self, cx: &App) -> bool {
17946        self.blame()
17947            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17948    }
17949
17950    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17951        let cursor_anchor = self.selections.newest_anchor().head();
17952
17953        let snapshot = self.buffer.read(cx).snapshot(cx);
17954        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17955
17956        snapshot.line_len(buffer_row) == 0
17957    }
17958
17959    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17960        let buffer_and_selection = maybe!({
17961            let selection = self.selections.newest::<Point>(cx);
17962            let selection_range = selection.range();
17963
17964            let multi_buffer = self.buffer().read(cx);
17965            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17966            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17967
17968            let (buffer, range, _) = if selection.reversed {
17969                buffer_ranges.first()
17970            } else {
17971                buffer_ranges.last()
17972            }?;
17973
17974            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17975                ..text::ToPoint::to_point(&range.end, &buffer).row;
17976            Some((
17977                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17978                selection,
17979            ))
17980        });
17981
17982        let Some((buffer, selection)) = buffer_and_selection else {
17983            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17984        };
17985
17986        let Some(project) = self.project.as_ref() else {
17987            return Task::ready(Err(anyhow!("editor does not have project")));
17988        };
17989
17990        project.update(cx, |project, cx| {
17991            project.get_permalink_to_line(&buffer, selection, cx)
17992        })
17993    }
17994
17995    pub fn copy_permalink_to_line(
17996        &mut self,
17997        _: &CopyPermalinkToLine,
17998        window: &mut Window,
17999        cx: &mut Context<Self>,
18000    ) {
18001        let permalink_task = self.get_permalink_to_line(cx);
18002        let workspace = self.workspace();
18003
18004        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18005            Ok(permalink) => {
18006                cx.update(|_, cx| {
18007                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18008                })
18009                .ok();
18010            }
18011            Err(err) => {
18012                let message = format!("Failed to copy permalink: {err}");
18013
18014                anyhow::Result::<()>::Err(err).log_err();
18015
18016                if let Some(workspace) = workspace {
18017                    workspace
18018                        .update_in(cx, |workspace, _, cx| {
18019                            struct CopyPermalinkToLine;
18020
18021                            workspace.show_toast(
18022                                Toast::new(
18023                                    NotificationId::unique::<CopyPermalinkToLine>(),
18024                                    message,
18025                                ),
18026                                cx,
18027                            )
18028                        })
18029                        .ok();
18030                }
18031            }
18032        })
18033        .detach();
18034    }
18035
18036    pub fn copy_file_location(
18037        &mut self,
18038        _: &CopyFileLocation,
18039        _: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18043        if let Some(file) = self.target_file(cx) {
18044            if let Some(path) = file.path().to_str() {
18045                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18046            }
18047        }
18048    }
18049
18050    pub fn open_permalink_to_line(
18051        &mut self,
18052        _: &OpenPermalinkToLine,
18053        window: &mut Window,
18054        cx: &mut Context<Self>,
18055    ) {
18056        let permalink_task = self.get_permalink_to_line(cx);
18057        let workspace = self.workspace();
18058
18059        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18060            Ok(permalink) => {
18061                cx.update(|_, cx| {
18062                    cx.open_url(permalink.as_ref());
18063                })
18064                .ok();
18065            }
18066            Err(err) => {
18067                let message = format!("Failed to open permalink: {err}");
18068
18069                anyhow::Result::<()>::Err(err).log_err();
18070
18071                if let Some(workspace) = workspace {
18072                    workspace
18073                        .update(cx, |workspace, cx| {
18074                            struct OpenPermalinkToLine;
18075
18076                            workspace.show_toast(
18077                                Toast::new(
18078                                    NotificationId::unique::<OpenPermalinkToLine>(),
18079                                    message,
18080                                ),
18081                                cx,
18082                            )
18083                        })
18084                        .ok();
18085                }
18086            }
18087        })
18088        .detach();
18089    }
18090
18091    pub fn insert_uuid_v4(
18092        &mut self,
18093        _: &InsertUuidV4,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) {
18097        self.insert_uuid(UuidVersion::V4, window, cx);
18098    }
18099
18100    pub fn insert_uuid_v7(
18101        &mut self,
18102        _: &InsertUuidV7,
18103        window: &mut Window,
18104        cx: &mut Context<Self>,
18105    ) {
18106        self.insert_uuid(UuidVersion::V7, window, cx);
18107    }
18108
18109    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18110        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18111        self.transact(window, cx, |this, window, cx| {
18112            let edits = this
18113                .selections
18114                .all::<Point>(cx)
18115                .into_iter()
18116                .map(|selection| {
18117                    let uuid = match version {
18118                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18119                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18120                    };
18121
18122                    (selection.range(), uuid.to_string())
18123                });
18124            this.edit(edits, cx);
18125            this.refresh_inline_completion(true, false, window, cx);
18126        });
18127    }
18128
18129    pub fn open_selections_in_multibuffer(
18130        &mut self,
18131        _: &OpenSelectionsInMultibuffer,
18132        window: &mut Window,
18133        cx: &mut Context<Self>,
18134    ) {
18135        let multibuffer = self.buffer.read(cx);
18136
18137        let Some(buffer) = multibuffer.as_singleton() else {
18138            return;
18139        };
18140
18141        let Some(workspace) = self.workspace() else {
18142            return;
18143        };
18144
18145        let locations = self
18146            .selections
18147            .disjoint_anchors()
18148            .iter()
18149            .map(|range| Location {
18150                buffer: buffer.clone(),
18151                range: range.start.text_anchor..range.end.text_anchor,
18152            })
18153            .collect::<Vec<_>>();
18154
18155        let title = multibuffer.title(cx).to_string();
18156
18157        cx.spawn_in(window, async move |_, cx| {
18158            workspace.update_in(cx, |workspace, window, cx| {
18159                Self::open_locations_in_multibuffer(
18160                    workspace,
18161                    locations,
18162                    format!("Selections for '{title}'"),
18163                    false,
18164                    MultibufferSelectionMode::All,
18165                    window,
18166                    cx,
18167                );
18168            })
18169        })
18170        .detach();
18171    }
18172
18173    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18174    /// last highlight added will be used.
18175    ///
18176    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18177    pub fn highlight_rows<T: 'static>(
18178        &mut self,
18179        range: Range<Anchor>,
18180        color: Hsla,
18181        options: RowHighlightOptions,
18182        cx: &mut Context<Self>,
18183    ) {
18184        let snapshot = self.buffer().read(cx).snapshot(cx);
18185        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18186        let ix = row_highlights.binary_search_by(|highlight| {
18187            Ordering::Equal
18188                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18189                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18190        });
18191
18192        if let Err(mut ix) = ix {
18193            let index = post_inc(&mut self.highlight_order);
18194
18195            // If this range intersects with the preceding highlight, then merge it with
18196            // the preceding highlight. Otherwise insert a new highlight.
18197            let mut merged = false;
18198            if ix > 0 {
18199                let prev_highlight = &mut row_highlights[ix - 1];
18200                if prev_highlight
18201                    .range
18202                    .end
18203                    .cmp(&range.start, &snapshot)
18204                    .is_ge()
18205                {
18206                    ix -= 1;
18207                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18208                        prev_highlight.range.end = range.end;
18209                    }
18210                    merged = true;
18211                    prev_highlight.index = index;
18212                    prev_highlight.color = color;
18213                    prev_highlight.options = options;
18214                }
18215            }
18216
18217            if !merged {
18218                row_highlights.insert(
18219                    ix,
18220                    RowHighlight {
18221                        range: range.clone(),
18222                        index,
18223                        color,
18224                        options,
18225                        type_id: TypeId::of::<T>(),
18226                    },
18227                );
18228            }
18229
18230            // If any of the following highlights intersect with this one, merge them.
18231            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18232                let highlight = &row_highlights[ix];
18233                if next_highlight
18234                    .range
18235                    .start
18236                    .cmp(&highlight.range.end, &snapshot)
18237                    .is_le()
18238                {
18239                    if next_highlight
18240                        .range
18241                        .end
18242                        .cmp(&highlight.range.end, &snapshot)
18243                        .is_gt()
18244                    {
18245                        row_highlights[ix].range.end = next_highlight.range.end;
18246                    }
18247                    row_highlights.remove(ix + 1);
18248                } else {
18249                    break;
18250                }
18251            }
18252        }
18253    }
18254
18255    /// Remove any highlighted row ranges of the given type that intersect the
18256    /// given ranges.
18257    pub fn remove_highlighted_rows<T: 'static>(
18258        &mut self,
18259        ranges_to_remove: Vec<Range<Anchor>>,
18260        cx: &mut Context<Self>,
18261    ) {
18262        let snapshot = self.buffer().read(cx).snapshot(cx);
18263        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18264        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18265        row_highlights.retain(|highlight| {
18266            while let Some(range_to_remove) = ranges_to_remove.peek() {
18267                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18268                    Ordering::Less | Ordering::Equal => {
18269                        ranges_to_remove.next();
18270                    }
18271                    Ordering::Greater => {
18272                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18273                            Ordering::Less | Ordering::Equal => {
18274                                return false;
18275                            }
18276                            Ordering::Greater => break,
18277                        }
18278                    }
18279                }
18280            }
18281
18282            true
18283        })
18284    }
18285
18286    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18287    pub fn clear_row_highlights<T: 'static>(&mut self) {
18288        self.highlighted_rows.remove(&TypeId::of::<T>());
18289    }
18290
18291    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18292    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18293        self.highlighted_rows
18294            .get(&TypeId::of::<T>())
18295            .map_or(&[] as &[_], |vec| vec.as_slice())
18296            .iter()
18297            .map(|highlight| (highlight.range.clone(), highlight.color))
18298    }
18299
18300    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18301    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18302    /// Allows to ignore certain kinds of highlights.
18303    pub fn highlighted_display_rows(
18304        &self,
18305        window: &mut Window,
18306        cx: &mut App,
18307    ) -> BTreeMap<DisplayRow, LineHighlight> {
18308        let snapshot = self.snapshot(window, cx);
18309        let mut used_highlight_orders = HashMap::default();
18310        self.highlighted_rows
18311            .iter()
18312            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18313            .fold(
18314                BTreeMap::<DisplayRow, LineHighlight>::new(),
18315                |mut unique_rows, highlight| {
18316                    let start = highlight.range.start.to_display_point(&snapshot);
18317                    let end = highlight.range.end.to_display_point(&snapshot);
18318                    let start_row = start.row().0;
18319                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18320                        && end.column() == 0
18321                    {
18322                        end.row().0.saturating_sub(1)
18323                    } else {
18324                        end.row().0
18325                    };
18326                    for row in start_row..=end_row {
18327                        let used_index =
18328                            used_highlight_orders.entry(row).or_insert(highlight.index);
18329                        if highlight.index >= *used_index {
18330                            *used_index = highlight.index;
18331                            unique_rows.insert(
18332                                DisplayRow(row),
18333                                LineHighlight {
18334                                    include_gutter: highlight.options.include_gutter,
18335                                    border: None,
18336                                    background: highlight.color.into(),
18337                                    type_id: Some(highlight.type_id),
18338                                },
18339                            );
18340                        }
18341                    }
18342                    unique_rows
18343                },
18344            )
18345    }
18346
18347    pub fn highlighted_display_row_for_autoscroll(
18348        &self,
18349        snapshot: &DisplaySnapshot,
18350    ) -> Option<DisplayRow> {
18351        self.highlighted_rows
18352            .values()
18353            .flat_map(|highlighted_rows| highlighted_rows.iter())
18354            .filter_map(|highlight| {
18355                if highlight.options.autoscroll {
18356                    Some(highlight.range.start.to_display_point(snapshot).row())
18357                } else {
18358                    None
18359                }
18360            })
18361            .min()
18362    }
18363
18364    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18365        self.highlight_background::<SearchWithinRange>(
18366            ranges,
18367            |colors| colors.editor_document_highlight_read_background,
18368            cx,
18369        )
18370    }
18371
18372    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18373        self.breadcrumb_header = Some(new_header);
18374    }
18375
18376    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18377        self.clear_background_highlights::<SearchWithinRange>(cx);
18378    }
18379
18380    pub fn highlight_background<T: 'static>(
18381        &mut self,
18382        ranges: &[Range<Anchor>],
18383        color_fetcher: fn(&ThemeColors) -> Hsla,
18384        cx: &mut Context<Self>,
18385    ) {
18386        self.background_highlights
18387            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18388        self.scrollbar_marker_state.dirty = true;
18389        cx.notify();
18390    }
18391
18392    pub fn clear_background_highlights<T: 'static>(
18393        &mut self,
18394        cx: &mut Context<Self>,
18395    ) -> Option<BackgroundHighlight> {
18396        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18397        if !text_highlights.1.is_empty() {
18398            self.scrollbar_marker_state.dirty = true;
18399            cx.notify();
18400        }
18401        Some(text_highlights)
18402    }
18403
18404    pub fn highlight_gutter<T: 'static>(
18405        &mut self,
18406        ranges: impl Into<Vec<Range<Anchor>>>,
18407        color_fetcher: fn(&App) -> Hsla,
18408        cx: &mut Context<Self>,
18409    ) {
18410        self.gutter_highlights
18411            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18412        cx.notify();
18413    }
18414
18415    pub fn clear_gutter_highlights<T: 'static>(
18416        &mut self,
18417        cx: &mut Context<Self>,
18418    ) -> Option<GutterHighlight> {
18419        cx.notify();
18420        self.gutter_highlights.remove(&TypeId::of::<T>())
18421    }
18422
18423    pub fn insert_gutter_highlight<T: 'static>(
18424        &mut self,
18425        range: Range<Anchor>,
18426        color_fetcher: fn(&App) -> Hsla,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let snapshot = self.buffer().read(cx).snapshot(cx);
18430        let mut highlights = self
18431            .gutter_highlights
18432            .remove(&TypeId::of::<T>())
18433            .map(|(_, highlights)| highlights)
18434            .unwrap_or_default();
18435        let ix = highlights.binary_search_by(|highlight| {
18436            Ordering::Equal
18437                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18438                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18439        });
18440        if let Err(ix) = ix {
18441            highlights.insert(ix, range);
18442        }
18443        self.gutter_highlights
18444            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18445    }
18446
18447    pub fn remove_gutter_highlights<T: 'static>(
18448        &mut self,
18449        ranges_to_remove: Vec<Range<Anchor>>,
18450        cx: &mut Context<Self>,
18451    ) {
18452        let snapshot = self.buffer().read(cx).snapshot(cx);
18453        let Some((color_fetcher, mut gutter_highlights)) =
18454            self.gutter_highlights.remove(&TypeId::of::<T>())
18455        else {
18456            return;
18457        };
18458        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18459        gutter_highlights.retain(|highlight| {
18460            while let Some(range_to_remove) = ranges_to_remove.peek() {
18461                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18462                    Ordering::Less | Ordering::Equal => {
18463                        ranges_to_remove.next();
18464                    }
18465                    Ordering::Greater => {
18466                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18467                            Ordering::Less | Ordering::Equal => {
18468                                return false;
18469                            }
18470                            Ordering::Greater => break,
18471                        }
18472                    }
18473                }
18474            }
18475
18476            true
18477        });
18478        self.gutter_highlights
18479            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18480    }
18481
18482    #[cfg(feature = "test-support")]
18483    pub fn all_text_background_highlights(
18484        &self,
18485        window: &mut Window,
18486        cx: &mut Context<Self>,
18487    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18488        let snapshot = self.snapshot(window, cx);
18489        let buffer = &snapshot.buffer_snapshot;
18490        let start = buffer.anchor_before(0);
18491        let end = buffer.anchor_after(buffer.len());
18492        let theme = cx.theme().colors();
18493        self.background_highlights_in_range(start..end, &snapshot, theme)
18494    }
18495
18496    #[cfg(feature = "test-support")]
18497    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18498        let snapshot = self.buffer().read(cx).snapshot(cx);
18499
18500        let highlights = self
18501            .background_highlights
18502            .get(&TypeId::of::<items::BufferSearchHighlights>());
18503
18504        if let Some((_color, ranges)) = highlights {
18505            ranges
18506                .iter()
18507                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18508                .collect_vec()
18509        } else {
18510            vec![]
18511        }
18512    }
18513
18514    fn document_highlights_for_position<'a>(
18515        &'a self,
18516        position: Anchor,
18517        buffer: &'a MultiBufferSnapshot,
18518    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18519        let read_highlights = self
18520            .background_highlights
18521            .get(&TypeId::of::<DocumentHighlightRead>())
18522            .map(|h| &h.1);
18523        let write_highlights = self
18524            .background_highlights
18525            .get(&TypeId::of::<DocumentHighlightWrite>())
18526            .map(|h| &h.1);
18527        let left_position = position.bias_left(buffer);
18528        let right_position = position.bias_right(buffer);
18529        read_highlights
18530            .into_iter()
18531            .chain(write_highlights)
18532            .flat_map(move |ranges| {
18533                let start_ix = match ranges.binary_search_by(|probe| {
18534                    let cmp = probe.end.cmp(&left_position, buffer);
18535                    if cmp.is_ge() {
18536                        Ordering::Greater
18537                    } else {
18538                        Ordering::Less
18539                    }
18540                }) {
18541                    Ok(i) | Err(i) => i,
18542                };
18543
18544                ranges[start_ix..]
18545                    .iter()
18546                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18547            })
18548    }
18549
18550    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18551        self.background_highlights
18552            .get(&TypeId::of::<T>())
18553            .map_or(false, |(_, highlights)| !highlights.is_empty())
18554    }
18555
18556    pub fn background_highlights_in_range(
18557        &self,
18558        search_range: Range<Anchor>,
18559        display_snapshot: &DisplaySnapshot,
18560        theme: &ThemeColors,
18561    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18562        let mut results = Vec::new();
18563        for (color_fetcher, ranges) in self.background_highlights.values() {
18564            let color = color_fetcher(theme);
18565            let start_ix = match ranges.binary_search_by(|probe| {
18566                let cmp = probe
18567                    .end
18568                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18569                if cmp.is_gt() {
18570                    Ordering::Greater
18571                } else {
18572                    Ordering::Less
18573                }
18574            }) {
18575                Ok(i) | Err(i) => i,
18576            };
18577            for range in &ranges[start_ix..] {
18578                if range
18579                    .start
18580                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18581                    .is_ge()
18582                {
18583                    break;
18584                }
18585
18586                let start = range.start.to_display_point(display_snapshot);
18587                let end = range.end.to_display_point(display_snapshot);
18588                results.push((start..end, color))
18589            }
18590        }
18591        results
18592    }
18593
18594    pub fn background_highlight_row_ranges<T: 'static>(
18595        &self,
18596        search_range: Range<Anchor>,
18597        display_snapshot: &DisplaySnapshot,
18598        count: usize,
18599    ) -> Vec<RangeInclusive<DisplayPoint>> {
18600        let mut results = Vec::new();
18601        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18602            return vec![];
18603        };
18604
18605        let start_ix = match ranges.binary_search_by(|probe| {
18606            let cmp = probe
18607                .end
18608                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18609            if cmp.is_gt() {
18610                Ordering::Greater
18611            } else {
18612                Ordering::Less
18613            }
18614        }) {
18615            Ok(i) | Err(i) => i,
18616        };
18617        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18618            if let (Some(start_display), Some(end_display)) = (start, end) {
18619                results.push(
18620                    start_display.to_display_point(display_snapshot)
18621                        ..=end_display.to_display_point(display_snapshot),
18622                );
18623            }
18624        };
18625        let mut start_row: Option<Point> = None;
18626        let mut end_row: Option<Point> = None;
18627        if ranges.len() > count {
18628            return Vec::new();
18629        }
18630        for range in &ranges[start_ix..] {
18631            if range
18632                .start
18633                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18634                .is_ge()
18635            {
18636                break;
18637            }
18638            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18639            if let Some(current_row) = &end_row {
18640                if end.row == current_row.row {
18641                    continue;
18642                }
18643            }
18644            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18645            if start_row.is_none() {
18646                assert_eq!(end_row, None);
18647                start_row = Some(start);
18648                end_row = Some(end);
18649                continue;
18650            }
18651            if let Some(current_end) = end_row.as_mut() {
18652                if start.row > current_end.row + 1 {
18653                    push_region(start_row, end_row);
18654                    start_row = Some(start);
18655                    end_row = Some(end);
18656                } else {
18657                    // Merge two hunks.
18658                    *current_end = end;
18659                }
18660            } else {
18661                unreachable!();
18662            }
18663        }
18664        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18665        push_region(start_row, end_row);
18666        results
18667    }
18668
18669    pub fn gutter_highlights_in_range(
18670        &self,
18671        search_range: Range<Anchor>,
18672        display_snapshot: &DisplaySnapshot,
18673        cx: &App,
18674    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18675        let mut results = Vec::new();
18676        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18677            let color = color_fetcher(cx);
18678            let start_ix = match ranges.binary_search_by(|probe| {
18679                let cmp = probe
18680                    .end
18681                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18682                if cmp.is_gt() {
18683                    Ordering::Greater
18684                } else {
18685                    Ordering::Less
18686                }
18687            }) {
18688                Ok(i) | Err(i) => i,
18689            };
18690            for range in &ranges[start_ix..] {
18691                if range
18692                    .start
18693                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18694                    .is_ge()
18695                {
18696                    break;
18697                }
18698
18699                let start = range.start.to_display_point(display_snapshot);
18700                let end = range.end.to_display_point(display_snapshot);
18701                results.push((start..end, color))
18702            }
18703        }
18704        results
18705    }
18706
18707    /// Get the text ranges corresponding to the redaction query
18708    pub fn redacted_ranges(
18709        &self,
18710        search_range: Range<Anchor>,
18711        display_snapshot: &DisplaySnapshot,
18712        cx: &App,
18713    ) -> Vec<Range<DisplayPoint>> {
18714        display_snapshot
18715            .buffer_snapshot
18716            .redacted_ranges(search_range, |file| {
18717                if let Some(file) = file {
18718                    file.is_private()
18719                        && EditorSettings::get(
18720                            Some(SettingsLocation {
18721                                worktree_id: file.worktree_id(cx),
18722                                path: file.path().as_ref(),
18723                            }),
18724                            cx,
18725                        )
18726                        .redact_private_values
18727                } else {
18728                    false
18729                }
18730            })
18731            .map(|range| {
18732                range.start.to_display_point(display_snapshot)
18733                    ..range.end.to_display_point(display_snapshot)
18734            })
18735            .collect()
18736    }
18737
18738    pub fn highlight_text<T: 'static>(
18739        &mut self,
18740        ranges: Vec<Range<Anchor>>,
18741        style: HighlightStyle,
18742        cx: &mut Context<Self>,
18743    ) {
18744        self.display_map.update(cx, |map, _| {
18745            map.highlight_text(TypeId::of::<T>(), ranges, style)
18746        });
18747        cx.notify();
18748    }
18749
18750    pub(crate) fn highlight_inlays<T: 'static>(
18751        &mut self,
18752        highlights: Vec<InlayHighlight>,
18753        style: HighlightStyle,
18754        cx: &mut Context<Self>,
18755    ) {
18756        self.display_map.update(cx, |map, _| {
18757            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18758        });
18759        cx.notify();
18760    }
18761
18762    pub fn text_highlights<'a, T: 'static>(
18763        &'a self,
18764        cx: &'a App,
18765    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18766        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18767    }
18768
18769    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18770        let cleared = self
18771            .display_map
18772            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18773        if cleared {
18774            cx.notify();
18775        }
18776    }
18777
18778    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18779        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18780            && self.focus_handle.is_focused(window)
18781    }
18782
18783    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18784        self.show_cursor_when_unfocused = is_enabled;
18785        cx.notify();
18786    }
18787
18788    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18789        cx.notify();
18790    }
18791
18792    fn on_debug_session_event(
18793        &mut self,
18794        _session: Entity<Session>,
18795        event: &SessionEvent,
18796        cx: &mut Context<Self>,
18797    ) {
18798        match event {
18799            SessionEvent::InvalidateInlineValue => {
18800                self.refresh_inline_values(cx);
18801            }
18802            _ => {}
18803        }
18804    }
18805
18806    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18807        let Some(project) = self.project.clone() else {
18808            return;
18809        };
18810
18811        if !self.inline_value_cache.enabled {
18812            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18813            self.splice_inlays(&inlays, Vec::new(), cx);
18814            return;
18815        }
18816
18817        let current_execution_position = self
18818            .highlighted_rows
18819            .get(&TypeId::of::<ActiveDebugLine>())
18820            .and_then(|lines| lines.last().map(|line| line.range.start));
18821
18822        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18823            let inline_values = editor
18824                .update(cx, |editor, cx| {
18825                    let Some(current_execution_position) = current_execution_position else {
18826                        return Some(Task::ready(Ok(Vec::new())));
18827                    };
18828
18829                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18830                        let snapshot = buffer.snapshot(cx);
18831
18832                        let excerpt = snapshot.excerpt_containing(
18833                            current_execution_position..current_execution_position,
18834                        )?;
18835
18836                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18837                    })?;
18838
18839                    let range =
18840                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18841
18842                    project.inline_values(buffer, range, cx)
18843                })
18844                .ok()
18845                .flatten()?
18846                .await
18847                .context("refreshing debugger inlays")
18848                .log_err()?;
18849
18850            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18851
18852            for (buffer_id, inline_value) in inline_values
18853                .into_iter()
18854                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18855            {
18856                buffer_inline_values
18857                    .entry(buffer_id)
18858                    .or_default()
18859                    .push(inline_value);
18860            }
18861
18862            editor
18863                .update(cx, |editor, cx| {
18864                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18865                    let mut new_inlays = Vec::default();
18866
18867                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18868                        let buffer_id = buffer_snapshot.remote_id();
18869                        buffer_inline_values
18870                            .get(&buffer_id)
18871                            .into_iter()
18872                            .flatten()
18873                            .for_each(|hint| {
18874                                let inlay = Inlay::debugger_hint(
18875                                    post_inc(&mut editor.next_inlay_id),
18876                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18877                                    hint.text(),
18878                                );
18879
18880                                new_inlays.push(inlay);
18881                            });
18882                    }
18883
18884                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18885                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18886
18887                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18888                })
18889                .ok()?;
18890            Some(())
18891        });
18892    }
18893
18894    fn on_buffer_event(
18895        &mut self,
18896        multibuffer: &Entity<MultiBuffer>,
18897        event: &multi_buffer::Event,
18898        window: &mut Window,
18899        cx: &mut Context<Self>,
18900    ) {
18901        match event {
18902            multi_buffer::Event::Edited {
18903                singleton_buffer_edited,
18904                edited_buffer,
18905            } => {
18906                self.scrollbar_marker_state.dirty = true;
18907                self.active_indent_guides_state.dirty = true;
18908                self.refresh_active_diagnostics(cx);
18909                self.refresh_code_actions(window, cx);
18910                self.refresh_selected_text_highlights(true, window, cx);
18911                refresh_matching_bracket_highlights(self, window, cx);
18912                if self.has_active_inline_completion() {
18913                    self.update_visible_inline_completion(window, cx);
18914                }
18915                if let Some(project) = self.project.as_ref() {
18916                    if let Some(edited_buffer) = edited_buffer {
18917                        project.update(cx, |project, cx| {
18918                            self.registered_buffers
18919                                .entry(edited_buffer.read(cx).remote_id())
18920                                .or_insert_with(|| {
18921                                    project
18922                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18923                                });
18924                        });
18925                        if edited_buffer.read(cx).file().is_some() {
18926                            self.pull_diagnostics(
18927                                Some(edited_buffer.read(cx).remote_id()),
18928                                window,
18929                                cx,
18930                            );
18931                        }
18932                    }
18933                }
18934                cx.emit(EditorEvent::BufferEdited);
18935                cx.emit(SearchEvent::MatchesInvalidated);
18936                if *singleton_buffer_edited {
18937                    if let Some(buffer) = edited_buffer {
18938                        if buffer.read(cx).file().is_none() {
18939                            cx.emit(EditorEvent::TitleChanged);
18940                        }
18941                    }
18942                    if let Some(project) = &self.project {
18943                        #[allow(clippy::mutable_key_type)]
18944                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18945                            multibuffer
18946                                .all_buffers()
18947                                .into_iter()
18948                                .filter_map(|buffer| {
18949                                    buffer.update(cx, |buffer, cx| {
18950                                        let language = buffer.language()?;
18951                                        let should_discard = project.update(cx, |project, cx| {
18952                                            project.is_local()
18953                                                && !project.has_language_servers_for(buffer, cx)
18954                                        });
18955                                        should_discard.not().then_some(language.clone())
18956                                    })
18957                                })
18958                                .collect::<HashSet<_>>()
18959                        });
18960                        if !languages_affected.is_empty() {
18961                            self.refresh_inlay_hints(
18962                                InlayHintRefreshReason::BufferEdited(languages_affected),
18963                                cx,
18964                            );
18965                        }
18966                    }
18967                }
18968
18969                let Some(project) = &self.project else { return };
18970                let (telemetry, is_via_ssh) = {
18971                    let project = project.read(cx);
18972                    let telemetry = project.client().telemetry().clone();
18973                    let is_via_ssh = project.is_via_ssh();
18974                    (telemetry, is_via_ssh)
18975                };
18976                refresh_linked_ranges(self, window, cx);
18977                telemetry.log_edit_event("editor", is_via_ssh);
18978            }
18979            multi_buffer::Event::ExcerptsAdded {
18980                buffer,
18981                predecessor,
18982                excerpts,
18983            } => {
18984                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18985                let buffer_id = buffer.read(cx).remote_id();
18986                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18987                    if let Some(project) = &self.project {
18988                        update_uncommitted_diff_for_buffer(
18989                            cx.entity(),
18990                            project,
18991                            [buffer.clone()],
18992                            self.buffer.clone(),
18993                            cx,
18994                        )
18995                        .detach();
18996                    }
18997                }
18998                cx.emit(EditorEvent::ExcerptsAdded {
18999                    buffer: buffer.clone(),
19000                    predecessor: *predecessor,
19001                    excerpts: excerpts.clone(),
19002                });
19003                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19004            }
19005            multi_buffer::Event::ExcerptsRemoved {
19006                ids,
19007                removed_buffer_ids,
19008            } => {
19009                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19010                let buffer = self.buffer.read(cx);
19011                self.registered_buffers
19012                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19013                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19014                cx.emit(EditorEvent::ExcerptsRemoved {
19015                    ids: ids.clone(),
19016                    removed_buffer_ids: removed_buffer_ids.clone(),
19017                })
19018            }
19019            multi_buffer::Event::ExcerptsEdited {
19020                excerpt_ids,
19021                buffer_ids,
19022            } => {
19023                self.display_map.update(cx, |map, cx| {
19024                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19025                });
19026                cx.emit(EditorEvent::ExcerptsEdited {
19027                    ids: excerpt_ids.clone(),
19028                })
19029            }
19030            multi_buffer::Event::ExcerptsExpanded { ids } => {
19031                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19032                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19033            }
19034            multi_buffer::Event::Reparsed(buffer_id) => {
19035                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19036                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19037
19038                cx.emit(EditorEvent::Reparsed(*buffer_id));
19039            }
19040            multi_buffer::Event::DiffHunksToggled => {
19041                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19042            }
19043            multi_buffer::Event::LanguageChanged(buffer_id) => {
19044                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19045                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19046                cx.emit(EditorEvent::Reparsed(*buffer_id));
19047                cx.notify();
19048            }
19049            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19050            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19051            multi_buffer::Event::FileHandleChanged
19052            | multi_buffer::Event::Reloaded
19053            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19054            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19055            multi_buffer::Event::DiagnosticsUpdated => {
19056                self.update_diagnostics_state(window, cx);
19057            }
19058            _ => {}
19059        };
19060    }
19061
19062    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19063        self.refresh_active_diagnostics(cx);
19064        self.refresh_inline_diagnostics(true, window, cx);
19065        self.scrollbar_marker_state.dirty = true;
19066        cx.notify();
19067    }
19068
19069    pub fn start_temporary_diff_override(&mut self) {
19070        self.load_diff_task.take();
19071        self.temporary_diff_override = true;
19072    }
19073
19074    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19075        self.temporary_diff_override = false;
19076        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19077        self.buffer.update(cx, |buffer, cx| {
19078            buffer.set_all_diff_hunks_collapsed(cx);
19079        });
19080
19081        if let Some(project) = self.project.clone() {
19082            self.load_diff_task = Some(
19083                update_uncommitted_diff_for_buffer(
19084                    cx.entity(),
19085                    &project,
19086                    self.buffer.read(cx).all_buffers(),
19087                    self.buffer.clone(),
19088                    cx,
19089                )
19090                .shared(),
19091            );
19092        }
19093    }
19094
19095    fn on_display_map_changed(
19096        &mut self,
19097        _: Entity<DisplayMap>,
19098        _: &mut Window,
19099        cx: &mut Context<Self>,
19100    ) {
19101        cx.notify();
19102    }
19103
19104    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19105        let new_severity = if self.diagnostics_enabled() {
19106            EditorSettings::get_global(cx)
19107                .diagnostics_max_severity
19108                .unwrap_or(DiagnosticSeverity::Hint)
19109        } else {
19110            DiagnosticSeverity::Off
19111        };
19112        self.set_max_diagnostics_severity(new_severity, cx);
19113        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19114        self.update_edit_prediction_settings(cx);
19115        self.refresh_inline_completion(true, false, window, cx);
19116        self.refresh_inlay_hints(
19117            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19118                self.selections.newest_anchor().head(),
19119                &self.buffer.read(cx).snapshot(cx),
19120                cx,
19121            )),
19122            cx,
19123        );
19124
19125        let old_cursor_shape = self.cursor_shape;
19126
19127        {
19128            let editor_settings = EditorSettings::get_global(cx);
19129            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19130            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19131            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19132            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19133            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19134        }
19135
19136        if old_cursor_shape != self.cursor_shape {
19137            cx.emit(EditorEvent::CursorShapeChanged);
19138        }
19139
19140        let project_settings = ProjectSettings::get_global(cx);
19141        self.serialize_dirty_buffers =
19142            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19143
19144        if self.mode.is_full() {
19145            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19146            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19147            if self.show_inline_diagnostics != show_inline_diagnostics {
19148                self.show_inline_diagnostics = show_inline_diagnostics;
19149                self.refresh_inline_diagnostics(false, window, cx);
19150            }
19151
19152            if self.git_blame_inline_enabled != inline_blame_enabled {
19153                self.toggle_git_blame_inline_internal(false, window, cx);
19154            }
19155
19156            let minimap_settings = EditorSettings::get_global(cx).minimap;
19157            if self.minimap_visibility != MinimapVisibility::Disabled {
19158                if self.minimap_visibility.settings_visibility()
19159                    != minimap_settings.minimap_enabled()
19160                {
19161                    self.set_minimap_visibility(
19162                        MinimapVisibility::for_mode(self.mode(), cx),
19163                        window,
19164                        cx,
19165                    );
19166                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19167                    minimap_entity.update(cx, |minimap_editor, cx| {
19168                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19169                    })
19170                }
19171            }
19172        }
19173
19174        cx.notify();
19175    }
19176
19177    pub fn set_searchable(&mut self, searchable: bool) {
19178        self.searchable = searchable;
19179    }
19180
19181    pub fn searchable(&self) -> bool {
19182        self.searchable
19183    }
19184
19185    fn open_proposed_changes_editor(
19186        &mut self,
19187        _: &OpenProposedChangesEditor,
19188        window: &mut Window,
19189        cx: &mut Context<Self>,
19190    ) {
19191        let Some(workspace) = self.workspace() else {
19192            cx.propagate();
19193            return;
19194        };
19195
19196        let selections = self.selections.all::<usize>(cx);
19197        let multi_buffer = self.buffer.read(cx);
19198        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19199        let mut new_selections_by_buffer = HashMap::default();
19200        for selection in selections {
19201            for (buffer, range, _) in
19202                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19203            {
19204                let mut range = range.to_point(buffer);
19205                range.start.column = 0;
19206                range.end.column = buffer.line_len(range.end.row);
19207                new_selections_by_buffer
19208                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19209                    .or_insert(Vec::new())
19210                    .push(range)
19211            }
19212        }
19213
19214        let proposed_changes_buffers = new_selections_by_buffer
19215            .into_iter()
19216            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19217            .collect::<Vec<_>>();
19218        let proposed_changes_editor = cx.new(|cx| {
19219            ProposedChangesEditor::new(
19220                "Proposed changes",
19221                proposed_changes_buffers,
19222                self.project.clone(),
19223                window,
19224                cx,
19225            )
19226        });
19227
19228        window.defer(cx, move |window, cx| {
19229            workspace.update(cx, |workspace, cx| {
19230                workspace.active_pane().update(cx, |pane, cx| {
19231                    pane.add_item(
19232                        Box::new(proposed_changes_editor),
19233                        true,
19234                        true,
19235                        None,
19236                        window,
19237                        cx,
19238                    );
19239                });
19240            });
19241        });
19242    }
19243
19244    pub fn open_excerpts_in_split(
19245        &mut self,
19246        _: &OpenExcerptsSplit,
19247        window: &mut Window,
19248        cx: &mut Context<Self>,
19249    ) {
19250        self.open_excerpts_common(None, true, window, cx)
19251    }
19252
19253    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19254        self.open_excerpts_common(None, false, window, cx)
19255    }
19256
19257    fn open_excerpts_common(
19258        &mut self,
19259        jump_data: Option<JumpData>,
19260        split: bool,
19261        window: &mut Window,
19262        cx: &mut Context<Self>,
19263    ) {
19264        let Some(workspace) = self.workspace() else {
19265            cx.propagate();
19266            return;
19267        };
19268
19269        if self.buffer.read(cx).is_singleton() {
19270            cx.propagate();
19271            return;
19272        }
19273
19274        let mut new_selections_by_buffer = HashMap::default();
19275        match &jump_data {
19276            Some(JumpData::MultiBufferPoint {
19277                excerpt_id,
19278                position,
19279                anchor,
19280                line_offset_from_top,
19281            }) => {
19282                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19283                if let Some(buffer) = multi_buffer_snapshot
19284                    .buffer_id_for_excerpt(*excerpt_id)
19285                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19286                {
19287                    let buffer_snapshot = buffer.read(cx).snapshot();
19288                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19289                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19290                    } else {
19291                        buffer_snapshot.clip_point(*position, Bias::Left)
19292                    };
19293                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19294                    new_selections_by_buffer.insert(
19295                        buffer,
19296                        (
19297                            vec![jump_to_offset..jump_to_offset],
19298                            Some(*line_offset_from_top),
19299                        ),
19300                    );
19301                }
19302            }
19303            Some(JumpData::MultiBufferRow {
19304                row,
19305                line_offset_from_top,
19306            }) => {
19307                let point = MultiBufferPoint::new(row.0, 0);
19308                if let Some((buffer, buffer_point, _)) =
19309                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19310                {
19311                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19312                    new_selections_by_buffer
19313                        .entry(buffer)
19314                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19315                        .0
19316                        .push(buffer_offset..buffer_offset)
19317                }
19318            }
19319            None => {
19320                let selections = self.selections.all::<usize>(cx);
19321                let multi_buffer = self.buffer.read(cx);
19322                for selection in selections {
19323                    for (snapshot, range, _, anchor) in multi_buffer
19324                        .snapshot(cx)
19325                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19326                    {
19327                        if let Some(anchor) = anchor {
19328                            // selection is in a deleted hunk
19329                            let Some(buffer_id) = anchor.buffer_id else {
19330                                continue;
19331                            };
19332                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19333                                continue;
19334                            };
19335                            let offset = text::ToOffset::to_offset(
19336                                &anchor.text_anchor,
19337                                &buffer_handle.read(cx).snapshot(),
19338                            );
19339                            let range = offset..offset;
19340                            new_selections_by_buffer
19341                                .entry(buffer_handle)
19342                                .or_insert((Vec::new(), None))
19343                                .0
19344                                .push(range)
19345                        } else {
19346                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19347                            else {
19348                                continue;
19349                            };
19350                            new_selections_by_buffer
19351                                .entry(buffer_handle)
19352                                .or_insert((Vec::new(), None))
19353                                .0
19354                                .push(range)
19355                        }
19356                    }
19357                }
19358            }
19359        }
19360
19361        new_selections_by_buffer
19362            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19363
19364        if new_selections_by_buffer.is_empty() {
19365            return;
19366        }
19367
19368        // We defer the pane interaction because we ourselves are a workspace item
19369        // and activating a new item causes the pane to call a method on us reentrantly,
19370        // which panics if we're on the stack.
19371        window.defer(cx, move |window, cx| {
19372            workspace.update(cx, |workspace, cx| {
19373                let pane = if split {
19374                    workspace.adjacent_pane(window, cx)
19375                } else {
19376                    workspace.active_pane().clone()
19377                };
19378
19379                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19380                    let editor = buffer
19381                        .read(cx)
19382                        .file()
19383                        .is_none()
19384                        .then(|| {
19385                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19386                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19387                            // Instead, we try to activate the existing editor in the pane first.
19388                            let (editor, pane_item_index) =
19389                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19390                                    let editor = item.downcast::<Editor>()?;
19391                                    let singleton_buffer =
19392                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19393                                    if singleton_buffer == buffer {
19394                                        Some((editor, i))
19395                                    } else {
19396                                        None
19397                                    }
19398                                })?;
19399                            pane.update(cx, |pane, cx| {
19400                                pane.activate_item(pane_item_index, true, true, window, cx)
19401                            });
19402                            Some(editor)
19403                        })
19404                        .flatten()
19405                        .unwrap_or_else(|| {
19406                            workspace.open_project_item::<Self>(
19407                                pane.clone(),
19408                                buffer,
19409                                true,
19410                                true,
19411                                window,
19412                                cx,
19413                            )
19414                        });
19415
19416                    editor.update(cx, |editor, cx| {
19417                        let autoscroll = match scroll_offset {
19418                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19419                            None => Autoscroll::newest(),
19420                        };
19421                        let nav_history = editor.nav_history.take();
19422                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19423                            s.select_ranges(ranges);
19424                        });
19425                        editor.nav_history = nav_history;
19426                    });
19427                }
19428            })
19429        });
19430    }
19431
19432    // For now, don't allow opening excerpts in buffers that aren't backed by
19433    // regular project files.
19434    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19435        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19436    }
19437
19438    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19439        let snapshot = self.buffer.read(cx).read(cx);
19440        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19441        Some(
19442            ranges
19443                .iter()
19444                .map(move |range| {
19445                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19446                })
19447                .collect(),
19448        )
19449    }
19450
19451    fn selection_replacement_ranges(
19452        &self,
19453        range: Range<OffsetUtf16>,
19454        cx: &mut App,
19455    ) -> Vec<Range<OffsetUtf16>> {
19456        let selections = self.selections.all::<OffsetUtf16>(cx);
19457        let newest_selection = selections
19458            .iter()
19459            .max_by_key(|selection| selection.id)
19460            .unwrap();
19461        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19462        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19463        let snapshot = self.buffer.read(cx).read(cx);
19464        selections
19465            .into_iter()
19466            .map(|mut selection| {
19467                selection.start.0 =
19468                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19469                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19470                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19471                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19472            })
19473            .collect()
19474    }
19475
19476    fn report_editor_event(
19477        &self,
19478        event_type: &'static str,
19479        file_extension: Option<String>,
19480        cx: &App,
19481    ) {
19482        if cfg!(any(test, feature = "test-support")) {
19483            return;
19484        }
19485
19486        let Some(project) = &self.project else { return };
19487
19488        // If None, we are in a file without an extension
19489        let file = self
19490            .buffer
19491            .read(cx)
19492            .as_singleton()
19493            .and_then(|b| b.read(cx).file());
19494        let file_extension = file_extension.or(file
19495            .as_ref()
19496            .and_then(|file| Path::new(file.file_name(cx)).extension())
19497            .and_then(|e| e.to_str())
19498            .map(|a| a.to_string()));
19499
19500        let vim_mode = vim_enabled(cx);
19501
19502        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19503        let copilot_enabled = edit_predictions_provider
19504            == language::language_settings::EditPredictionProvider::Copilot;
19505        let copilot_enabled_for_language = self
19506            .buffer
19507            .read(cx)
19508            .language_settings(cx)
19509            .show_edit_predictions;
19510
19511        let project = project.read(cx);
19512        telemetry::event!(
19513            event_type,
19514            file_extension,
19515            vim_mode,
19516            copilot_enabled,
19517            copilot_enabled_for_language,
19518            edit_predictions_provider,
19519            is_via_ssh = project.is_via_ssh(),
19520        );
19521    }
19522
19523    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19524    /// with each line being an array of {text, highlight} objects.
19525    fn copy_highlight_json(
19526        &mut self,
19527        _: &CopyHighlightJson,
19528        window: &mut Window,
19529        cx: &mut Context<Self>,
19530    ) {
19531        #[derive(Serialize)]
19532        struct Chunk<'a> {
19533            text: String,
19534            highlight: Option<&'a str>,
19535        }
19536
19537        let snapshot = self.buffer.read(cx).snapshot(cx);
19538        let range = self
19539            .selected_text_range(false, window, cx)
19540            .and_then(|selection| {
19541                if selection.range.is_empty() {
19542                    None
19543                } else {
19544                    Some(selection.range)
19545                }
19546            })
19547            .unwrap_or_else(|| 0..snapshot.len());
19548
19549        let chunks = snapshot.chunks(range, true);
19550        let mut lines = Vec::new();
19551        let mut line: VecDeque<Chunk> = VecDeque::new();
19552
19553        let Some(style) = self.style.as_ref() else {
19554            return;
19555        };
19556
19557        for chunk in chunks {
19558            let highlight = chunk
19559                .syntax_highlight_id
19560                .and_then(|id| id.name(&style.syntax));
19561            let mut chunk_lines = chunk.text.split('\n').peekable();
19562            while let Some(text) = chunk_lines.next() {
19563                let mut merged_with_last_token = false;
19564                if let Some(last_token) = line.back_mut() {
19565                    if last_token.highlight == highlight {
19566                        last_token.text.push_str(text);
19567                        merged_with_last_token = true;
19568                    }
19569                }
19570
19571                if !merged_with_last_token {
19572                    line.push_back(Chunk {
19573                        text: text.into(),
19574                        highlight,
19575                    });
19576                }
19577
19578                if chunk_lines.peek().is_some() {
19579                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19580                        line.pop_front();
19581                    }
19582                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19583                        line.pop_back();
19584                    }
19585
19586                    lines.push(mem::take(&mut line));
19587                }
19588            }
19589        }
19590
19591        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19592            return;
19593        };
19594        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19595    }
19596
19597    pub fn open_context_menu(
19598        &mut self,
19599        _: &OpenContextMenu,
19600        window: &mut Window,
19601        cx: &mut Context<Self>,
19602    ) {
19603        self.request_autoscroll(Autoscroll::newest(), cx);
19604        let position = self.selections.newest_display(cx).start;
19605        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19606    }
19607
19608    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19609        &self.inlay_hint_cache
19610    }
19611
19612    pub fn replay_insert_event(
19613        &mut self,
19614        text: &str,
19615        relative_utf16_range: Option<Range<isize>>,
19616        window: &mut Window,
19617        cx: &mut Context<Self>,
19618    ) {
19619        if !self.input_enabled {
19620            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19621            return;
19622        }
19623        if let Some(relative_utf16_range) = relative_utf16_range {
19624            let selections = self.selections.all::<OffsetUtf16>(cx);
19625            self.change_selections(None, window, cx, |s| {
19626                let new_ranges = selections.into_iter().map(|range| {
19627                    let start = OffsetUtf16(
19628                        range
19629                            .head()
19630                            .0
19631                            .saturating_add_signed(relative_utf16_range.start),
19632                    );
19633                    let end = OffsetUtf16(
19634                        range
19635                            .head()
19636                            .0
19637                            .saturating_add_signed(relative_utf16_range.end),
19638                    );
19639                    start..end
19640                });
19641                s.select_ranges(new_ranges);
19642            });
19643        }
19644
19645        self.handle_input(text, window, cx);
19646    }
19647
19648    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19649        let Some(provider) = self.semantics_provider.as_ref() else {
19650            return false;
19651        };
19652
19653        let mut supports = false;
19654        self.buffer().update(cx, |this, cx| {
19655            this.for_each_buffer(|buffer| {
19656                supports |= provider.supports_inlay_hints(buffer, cx);
19657            });
19658        });
19659
19660        supports
19661    }
19662
19663    pub fn is_focused(&self, window: &Window) -> bool {
19664        self.focus_handle.is_focused(window)
19665    }
19666
19667    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19668        cx.emit(EditorEvent::Focused);
19669
19670        if let Some(descendant) = self
19671            .last_focused_descendant
19672            .take()
19673            .and_then(|descendant| descendant.upgrade())
19674        {
19675            window.focus(&descendant);
19676        } else {
19677            if let Some(blame) = self.blame.as_ref() {
19678                blame.update(cx, GitBlame::focus)
19679            }
19680
19681            self.blink_manager.update(cx, BlinkManager::enable);
19682            self.show_cursor_names(window, cx);
19683            self.buffer.update(cx, |buffer, cx| {
19684                buffer.finalize_last_transaction(cx);
19685                if self.leader_id.is_none() {
19686                    buffer.set_active_selections(
19687                        &self.selections.disjoint_anchors(),
19688                        self.selections.line_mode,
19689                        self.cursor_shape,
19690                        cx,
19691                    );
19692                }
19693            });
19694        }
19695    }
19696
19697    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19698        cx.emit(EditorEvent::FocusedIn)
19699    }
19700
19701    fn handle_focus_out(
19702        &mut self,
19703        event: FocusOutEvent,
19704        _window: &mut Window,
19705        cx: &mut Context<Self>,
19706    ) {
19707        if event.blurred != self.focus_handle {
19708            self.last_focused_descendant = Some(event.blurred);
19709        }
19710        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19711    }
19712
19713    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19714        self.blink_manager.update(cx, BlinkManager::disable);
19715        self.buffer
19716            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19717
19718        if let Some(blame) = self.blame.as_ref() {
19719            blame.update(cx, GitBlame::blur)
19720        }
19721        if !self.hover_state.focused(window, cx) {
19722            hide_hover(self, cx);
19723        }
19724        if !self
19725            .context_menu
19726            .borrow()
19727            .as_ref()
19728            .is_some_and(|context_menu| context_menu.focused(window, cx))
19729        {
19730            self.hide_context_menu(window, cx);
19731        }
19732        self.discard_inline_completion(false, cx);
19733        cx.emit(EditorEvent::Blurred);
19734        cx.notify();
19735    }
19736
19737    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19738        let mut pending: String = window
19739            .pending_input_keystrokes()
19740            .into_iter()
19741            .flatten()
19742            .filter_map(|keystroke| {
19743                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19744                    keystroke.key_char.clone()
19745                } else {
19746                    None
19747                }
19748            })
19749            .collect();
19750
19751        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19752            pending = "".to_string();
19753        }
19754
19755        let existing_pending = self
19756            .text_highlights::<PendingInput>(cx)
19757            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19758        if existing_pending.is_none() && pending.is_empty() {
19759            return;
19760        }
19761        let transaction =
19762            self.transact(window, cx, |this, window, cx| {
19763                let selections = this.selections.all::<usize>(cx);
19764                let edits = selections
19765                    .iter()
19766                    .map(|selection| (selection.end..selection.end, pending.clone()));
19767                this.edit(edits, cx);
19768                this.change_selections(None, window, cx, |s| {
19769                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19770                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19771                    }));
19772                });
19773                if let Some(existing_ranges) = existing_pending {
19774                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19775                    this.edit(edits, cx);
19776                }
19777            });
19778
19779        let snapshot = self.snapshot(window, cx);
19780        let ranges = self
19781            .selections
19782            .all::<usize>(cx)
19783            .into_iter()
19784            .map(|selection| {
19785                snapshot.buffer_snapshot.anchor_after(selection.end)
19786                    ..snapshot
19787                        .buffer_snapshot
19788                        .anchor_before(selection.end + pending.len())
19789            })
19790            .collect();
19791
19792        if pending.is_empty() {
19793            self.clear_highlights::<PendingInput>(cx);
19794        } else {
19795            self.highlight_text::<PendingInput>(
19796                ranges,
19797                HighlightStyle {
19798                    underline: Some(UnderlineStyle {
19799                        thickness: px(1.),
19800                        color: None,
19801                        wavy: false,
19802                    }),
19803                    ..Default::default()
19804                },
19805                cx,
19806            );
19807        }
19808
19809        self.ime_transaction = self.ime_transaction.or(transaction);
19810        if let Some(transaction) = self.ime_transaction {
19811            self.buffer.update(cx, |buffer, cx| {
19812                buffer.group_until_transaction(transaction, cx);
19813            });
19814        }
19815
19816        if self.text_highlights::<PendingInput>(cx).is_none() {
19817            self.ime_transaction.take();
19818        }
19819    }
19820
19821    pub fn register_action_renderer(
19822        &mut self,
19823        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19824    ) -> Subscription {
19825        let id = self.next_editor_action_id.post_inc();
19826        self.editor_actions
19827            .borrow_mut()
19828            .insert(id, Box::new(listener));
19829
19830        let editor_actions = self.editor_actions.clone();
19831        Subscription::new(move || {
19832            editor_actions.borrow_mut().remove(&id);
19833        })
19834    }
19835
19836    pub fn register_action<A: Action>(
19837        &mut self,
19838        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19839    ) -> Subscription {
19840        let id = self.next_editor_action_id.post_inc();
19841        let listener = Arc::new(listener);
19842        self.editor_actions.borrow_mut().insert(
19843            id,
19844            Box::new(move |_, window, _| {
19845                let listener = listener.clone();
19846                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19847                    let action = action.downcast_ref().unwrap();
19848                    if phase == DispatchPhase::Bubble {
19849                        listener(action, window, cx)
19850                    }
19851                })
19852            }),
19853        );
19854
19855        let editor_actions = self.editor_actions.clone();
19856        Subscription::new(move || {
19857            editor_actions.borrow_mut().remove(&id);
19858        })
19859    }
19860
19861    pub fn file_header_size(&self) -> u32 {
19862        FILE_HEADER_HEIGHT
19863    }
19864
19865    pub fn restore(
19866        &mut self,
19867        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19868        window: &mut Window,
19869        cx: &mut Context<Self>,
19870    ) {
19871        let workspace = self.workspace();
19872        let project = self.project.as_ref();
19873        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19874            let mut tasks = Vec::new();
19875            for (buffer_id, changes) in revert_changes {
19876                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19877                    buffer.update(cx, |buffer, cx| {
19878                        buffer.edit(
19879                            changes
19880                                .into_iter()
19881                                .map(|(range, text)| (range, text.to_string())),
19882                            None,
19883                            cx,
19884                        );
19885                    });
19886
19887                    if let Some(project) =
19888                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19889                    {
19890                        project.update(cx, |project, cx| {
19891                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19892                        })
19893                    }
19894                }
19895            }
19896            tasks
19897        });
19898        cx.spawn_in(window, async move |_, cx| {
19899            for (buffer, task) in save_tasks {
19900                let result = task.await;
19901                if result.is_err() {
19902                    let Some(path) = buffer
19903                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19904                        .ok()
19905                    else {
19906                        continue;
19907                    };
19908                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19909                        let Some(task) = cx
19910                            .update_window_entity(&workspace, |workspace, window, cx| {
19911                                workspace
19912                                    .open_path_preview(path, None, false, false, false, window, cx)
19913                            })
19914                            .ok()
19915                        else {
19916                            continue;
19917                        };
19918                        task.await.log_err();
19919                    }
19920                }
19921            }
19922        })
19923        .detach();
19924        self.change_selections(None, window, cx, |selections| selections.refresh());
19925    }
19926
19927    pub fn to_pixel_point(
19928        &self,
19929        source: multi_buffer::Anchor,
19930        editor_snapshot: &EditorSnapshot,
19931        window: &mut Window,
19932    ) -> Option<gpui::Point<Pixels>> {
19933        let source_point = source.to_display_point(editor_snapshot);
19934        self.display_to_pixel_point(source_point, editor_snapshot, window)
19935    }
19936
19937    pub fn display_to_pixel_point(
19938        &self,
19939        source: DisplayPoint,
19940        editor_snapshot: &EditorSnapshot,
19941        window: &mut Window,
19942    ) -> Option<gpui::Point<Pixels>> {
19943        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19944        let text_layout_details = self.text_layout_details(window);
19945        let scroll_top = text_layout_details
19946            .scroll_anchor
19947            .scroll_position(editor_snapshot)
19948            .y;
19949
19950        if source.row().as_f32() < scroll_top.floor() {
19951            return None;
19952        }
19953        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19954        let source_y = line_height * (source.row().as_f32() - scroll_top);
19955        Some(gpui::Point::new(source_x, source_y))
19956    }
19957
19958    pub fn has_visible_completions_menu(&self) -> bool {
19959        !self.edit_prediction_preview_is_active()
19960            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19961                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19962            })
19963    }
19964
19965    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19966        if self.mode.is_minimap() {
19967            return;
19968        }
19969        self.addons
19970            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19971    }
19972
19973    pub fn unregister_addon<T: Addon>(&mut self) {
19974        self.addons.remove(&std::any::TypeId::of::<T>());
19975    }
19976
19977    pub fn addon<T: Addon>(&self) -> Option<&T> {
19978        let type_id = std::any::TypeId::of::<T>();
19979        self.addons
19980            .get(&type_id)
19981            .and_then(|item| item.to_any().downcast_ref::<T>())
19982    }
19983
19984    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19985        let type_id = std::any::TypeId::of::<T>();
19986        self.addons
19987            .get_mut(&type_id)
19988            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19989    }
19990
19991    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19992        let text_layout_details = self.text_layout_details(window);
19993        let style = &text_layout_details.editor_style;
19994        let font_id = window.text_system().resolve_font(&style.text.font());
19995        let font_size = style.text.font_size.to_pixels(window.rem_size());
19996        let line_height = style.text.line_height_in_pixels(window.rem_size());
19997        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19998
19999        gpui::Size::new(em_width, line_height)
20000    }
20001
20002    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20003        self.load_diff_task.clone()
20004    }
20005
20006    fn read_metadata_from_db(
20007        &mut self,
20008        item_id: u64,
20009        workspace_id: WorkspaceId,
20010        window: &mut Window,
20011        cx: &mut Context<Editor>,
20012    ) {
20013        if self.is_singleton(cx)
20014            && !self.mode.is_minimap()
20015            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20016        {
20017            let buffer_snapshot = OnceCell::new();
20018
20019            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20020                if !folds.is_empty() {
20021                    let snapshot =
20022                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20023                    self.fold_ranges(
20024                        folds
20025                            .into_iter()
20026                            .map(|(start, end)| {
20027                                snapshot.clip_offset(start, Bias::Left)
20028                                    ..snapshot.clip_offset(end, Bias::Right)
20029                            })
20030                            .collect(),
20031                        false,
20032                        window,
20033                        cx,
20034                    );
20035                }
20036            }
20037
20038            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20039                if !selections.is_empty() {
20040                    let snapshot =
20041                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20042                    // skip adding the initial selection to selection history
20043                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20044                    self.change_selections(None, window, cx, |s| {
20045                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20046                            snapshot.clip_offset(start, Bias::Left)
20047                                ..snapshot.clip_offset(end, Bias::Right)
20048                        }));
20049                    });
20050                    self.selection_history.mode = SelectionHistoryMode::Normal;
20051                }
20052            };
20053        }
20054
20055        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20056    }
20057}
20058
20059fn vim_enabled(cx: &App) -> bool {
20060    cx.global::<SettingsStore>()
20061        .raw_user_settings()
20062        .get("vim_mode")
20063        == Some(&serde_json::Value::Bool(true))
20064}
20065
20066fn process_completion_for_edit(
20067    completion: &Completion,
20068    intent: CompletionIntent,
20069    buffer: &Entity<Buffer>,
20070    cursor_position: &text::Anchor,
20071    cx: &mut Context<Editor>,
20072) -> CompletionEdit {
20073    let buffer = buffer.read(cx);
20074    let buffer_snapshot = buffer.snapshot();
20075    let (snippet, new_text) = if completion.is_snippet() {
20076        // Workaround for typescript language server issues so that methods don't expand within
20077        // strings and functions with type expressions. The previous point is used because the query
20078        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20079        let mut snippet_source = completion.new_text.clone();
20080        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20081        previous_point.column = previous_point.column.saturating_sub(1);
20082        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20083            if scope.prefers_label_for_snippet_in_completion() {
20084                if let Some(label) = completion.label() {
20085                    if matches!(
20086                        completion.kind(),
20087                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20088                    ) {
20089                        snippet_source = label;
20090                    }
20091                }
20092            }
20093        }
20094        match Snippet::parse(&snippet_source).log_err() {
20095            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20096            None => (None, completion.new_text.clone()),
20097        }
20098    } else {
20099        (None, completion.new_text.clone())
20100    };
20101
20102    let mut range_to_replace = {
20103        let replace_range = &completion.replace_range;
20104        if let CompletionSource::Lsp {
20105            insert_range: Some(insert_range),
20106            ..
20107        } = &completion.source
20108        {
20109            debug_assert_eq!(
20110                insert_range.start, replace_range.start,
20111                "insert_range and replace_range should start at the same position"
20112            );
20113            debug_assert!(
20114                insert_range
20115                    .start
20116                    .cmp(&cursor_position, &buffer_snapshot)
20117                    .is_le(),
20118                "insert_range should start before or at cursor position"
20119            );
20120            debug_assert!(
20121                replace_range
20122                    .start
20123                    .cmp(&cursor_position, &buffer_snapshot)
20124                    .is_le(),
20125                "replace_range should start before or at cursor position"
20126            );
20127            debug_assert!(
20128                insert_range
20129                    .end
20130                    .cmp(&cursor_position, &buffer_snapshot)
20131                    .is_le(),
20132                "insert_range should end before or at cursor position"
20133            );
20134
20135            let should_replace = match intent {
20136                CompletionIntent::CompleteWithInsert => false,
20137                CompletionIntent::CompleteWithReplace => true,
20138                CompletionIntent::Complete | CompletionIntent::Compose => {
20139                    let insert_mode =
20140                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20141                            .completions
20142                            .lsp_insert_mode;
20143                    match insert_mode {
20144                        LspInsertMode::Insert => false,
20145                        LspInsertMode::Replace => true,
20146                        LspInsertMode::ReplaceSubsequence => {
20147                            let mut text_to_replace = buffer.chars_for_range(
20148                                buffer.anchor_before(replace_range.start)
20149                                    ..buffer.anchor_after(replace_range.end),
20150                            );
20151                            let mut current_needle = text_to_replace.next();
20152                            for haystack_ch in completion.label.text.chars() {
20153                                if let Some(needle_ch) = current_needle {
20154                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20155                                        current_needle = text_to_replace.next();
20156                                    }
20157                                }
20158                            }
20159                            current_needle.is_none()
20160                        }
20161                        LspInsertMode::ReplaceSuffix => {
20162                            if replace_range
20163                                .end
20164                                .cmp(&cursor_position, &buffer_snapshot)
20165                                .is_gt()
20166                            {
20167                                let range_after_cursor = *cursor_position..replace_range.end;
20168                                let text_after_cursor = buffer
20169                                    .text_for_range(
20170                                        buffer.anchor_before(range_after_cursor.start)
20171                                            ..buffer.anchor_after(range_after_cursor.end),
20172                                    )
20173                                    .collect::<String>()
20174                                    .to_ascii_lowercase();
20175                                completion
20176                                    .label
20177                                    .text
20178                                    .to_ascii_lowercase()
20179                                    .ends_with(&text_after_cursor)
20180                            } else {
20181                                true
20182                            }
20183                        }
20184                    }
20185                }
20186            };
20187
20188            if should_replace {
20189                replace_range.clone()
20190            } else {
20191                insert_range.clone()
20192            }
20193        } else {
20194            replace_range.clone()
20195        }
20196    };
20197
20198    if range_to_replace
20199        .end
20200        .cmp(&cursor_position, &buffer_snapshot)
20201        .is_lt()
20202    {
20203        range_to_replace.end = *cursor_position;
20204    }
20205
20206    CompletionEdit {
20207        new_text,
20208        replace_range: range_to_replace.to_offset(&buffer),
20209        snippet,
20210    }
20211}
20212
20213struct CompletionEdit {
20214    new_text: String,
20215    replace_range: Range<usize>,
20216    snippet: Option<Snippet>,
20217}
20218
20219fn insert_extra_newline_brackets(
20220    buffer: &MultiBufferSnapshot,
20221    range: Range<usize>,
20222    language: &language::LanguageScope,
20223) -> bool {
20224    let leading_whitespace_len = buffer
20225        .reversed_chars_at(range.start)
20226        .take_while(|c| c.is_whitespace() && *c != '\n')
20227        .map(|c| c.len_utf8())
20228        .sum::<usize>();
20229    let trailing_whitespace_len = buffer
20230        .chars_at(range.end)
20231        .take_while(|c| c.is_whitespace() && *c != '\n')
20232        .map(|c| c.len_utf8())
20233        .sum::<usize>();
20234    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20235
20236    language.brackets().any(|(pair, enabled)| {
20237        let pair_start = pair.start.trim_end();
20238        let pair_end = pair.end.trim_start();
20239
20240        enabled
20241            && pair.newline
20242            && buffer.contains_str_at(range.end, pair_end)
20243            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20244    })
20245}
20246
20247fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20248    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20249        [(buffer, range, _)] => (*buffer, range.clone()),
20250        _ => return false,
20251    };
20252    let pair = {
20253        let mut result: Option<BracketMatch> = None;
20254
20255        for pair in buffer
20256            .all_bracket_ranges(range.clone())
20257            .filter(move |pair| {
20258                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20259            })
20260        {
20261            let len = pair.close_range.end - pair.open_range.start;
20262
20263            if let Some(existing) = &result {
20264                let existing_len = existing.close_range.end - existing.open_range.start;
20265                if len > existing_len {
20266                    continue;
20267                }
20268            }
20269
20270            result = Some(pair);
20271        }
20272
20273        result
20274    };
20275    let Some(pair) = pair else {
20276        return false;
20277    };
20278    pair.newline_only
20279        && buffer
20280            .chars_for_range(pair.open_range.end..range.start)
20281            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20282            .all(|c| c.is_whitespace() && c != '\n')
20283}
20284
20285fn update_uncommitted_diff_for_buffer(
20286    editor: Entity<Editor>,
20287    project: &Entity<Project>,
20288    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20289    buffer: Entity<MultiBuffer>,
20290    cx: &mut App,
20291) -> Task<()> {
20292    let mut tasks = Vec::new();
20293    project.update(cx, |project, cx| {
20294        for buffer in buffers {
20295            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20296                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20297            }
20298        }
20299    });
20300    cx.spawn(async move |cx| {
20301        let diffs = future::join_all(tasks).await;
20302        if editor
20303            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20304            .unwrap_or(false)
20305        {
20306            return;
20307        }
20308
20309        buffer
20310            .update(cx, |buffer, cx| {
20311                for diff in diffs.into_iter().flatten() {
20312                    buffer.add_diff(diff, cx);
20313                }
20314            })
20315            .ok();
20316    })
20317}
20318
20319fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20320    let tab_size = tab_size.get() as usize;
20321    let mut width = offset;
20322
20323    for ch in text.chars() {
20324        width += if ch == '\t' {
20325            tab_size - (width % tab_size)
20326        } else {
20327            1
20328        };
20329    }
20330
20331    width - offset
20332}
20333
20334#[cfg(test)]
20335mod tests {
20336    use super::*;
20337
20338    #[test]
20339    fn test_string_size_with_expanded_tabs() {
20340        let nz = |val| NonZeroU32::new(val).unwrap();
20341        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20342        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20343        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20344        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20345        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20346        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20347        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20348        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20349    }
20350}
20351
20352/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20353struct WordBreakingTokenizer<'a> {
20354    input: &'a str,
20355}
20356
20357impl<'a> WordBreakingTokenizer<'a> {
20358    fn new(input: &'a str) -> Self {
20359        Self { input }
20360    }
20361}
20362
20363fn is_char_ideographic(ch: char) -> bool {
20364    use unicode_script::Script::*;
20365    use unicode_script::UnicodeScript;
20366    matches!(ch.script(), Han | Tangut | Yi)
20367}
20368
20369fn is_grapheme_ideographic(text: &str) -> bool {
20370    text.chars().any(is_char_ideographic)
20371}
20372
20373fn is_grapheme_whitespace(text: &str) -> bool {
20374    text.chars().any(|x| x.is_whitespace())
20375}
20376
20377fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20378    text.chars().next().map_or(false, |ch| {
20379        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20380    })
20381}
20382
20383#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20384enum WordBreakToken<'a> {
20385    Word { token: &'a str, grapheme_len: usize },
20386    InlineWhitespace { token: &'a str, grapheme_len: usize },
20387    Newline,
20388}
20389
20390impl<'a> Iterator for WordBreakingTokenizer<'a> {
20391    /// Yields a span, the count of graphemes in the token, and whether it was
20392    /// whitespace. Note that it also breaks at word boundaries.
20393    type Item = WordBreakToken<'a>;
20394
20395    fn next(&mut self) -> Option<Self::Item> {
20396        use unicode_segmentation::UnicodeSegmentation;
20397        if self.input.is_empty() {
20398            return None;
20399        }
20400
20401        let mut iter = self.input.graphemes(true).peekable();
20402        let mut offset = 0;
20403        let mut grapheme_len = 0;
20404        if let Some(first_grapheme) = iter.next() {
20405            let is_newline = first_grapheme == "\n";
20406            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20407            offset += first_grapheme.len();
20408            grapheme_len += 1;
20409            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20410                if let Some(grapheme) = iter.peek().copied() {
20411                    if should_stay_with_preceding_ideograph(grapheme) {
20412                        offset += grapheme.len();
20413                        grapheme_len += 1;
20414                    }
20415                }
20416            } else {
20417                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20418                let mut next_word_bound = words.peek().copied();
20419                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20420                    next_word_bound = words.next();
20421                }
20422                while let Some(grapheme) = iter.peek().copied() {
20423                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20424                        break;
20425                    };
20426                    if is_grapheme_whitespace(grapheme) != is_whitespace
20427                        || (grapheme == "\n") != is_newline
20428                    {
20429                        break;
20430                    };
20431                    offset += grapheme.len();
20432                    grapheme_len += 1;
20433                    iter.next();
20434                }
20435            }
20436            let token = &self.input[..offset];
20437            self.input = &self.input[offset..];
20438            if token == "\n" {
20439                Some(WordBreakToken::Newline)
20440            } else if is_whitespace {
20441                Some(WordBreakToken::InlineWhitespace {
20442                    token,
20443                    grapheme_len,
20444                })
20445            } else {
20446                Some(WordBreakToken::Word {
20447                    token,
20448                    grapheme_len,
20449                })
20450            }
20451        } else {
20452            None
20453        }
20454    }
20455}
20456
20457#[test]
20458fn test_word_breaking_tokenizer() {
20459    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20460        ("", &[]),
20461        ("  ", &[whitespace("  ", 2)]),
20462        ("Ʒ", &[word("Ʒ", 1)]),
20463        ("Ǽ", &[word("Ǽ", 1)]),
20464        ("", &[word("", 1)]),
20465        ("⋑⋑", &[word("⋑⋑", 2)]),
20466        (
20467            "原理,进而",
20468            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20469        ),
20470        (
20471            "hello world",
20472            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20473        ),
20474        (
20475            "hello, world",
20476            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20477        ),
20478        (
20479            "  hello world",
20480            &[
20481                whitespace("  ", 2),
20482                word("hello", 5),
20483                whitespace(" ", 1),
20484                word("world", 5),
20485            ],
20486        ),
20487        (
20488            "这是什么 \n 钢笔",
20489            &[
20490                word("", 1),
20491                word("", 1),
20492                word("", 1),
20493                word("", 1),
20494                whitespace(" ", 1),
20495                newline(),
20496                whitespace(" ", 1),
20497                word("", 1),
20498                word("", 1),
20499            ],
20500        ),
20501        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20502    ];
20503
20504    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20505        WordBreakToken::Word {
20506            token,
20507            grapheme_len,
20508        }
20509    }
20510
20511    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20512        WordBreakToken::InlineWhitespace {
20513            token,
20514            grapheme_len,
20515        }
20516    }
20517
20518    fn newline() -> WordBreakToken<'static> {
20519        WordBreakToken::Newline
20520    }
20521
20522    for (input, result) in tests {
20523        assert_eq!(
20524            WordBreakingTokenizer::new(input)
20525                .collect::<Vec<_>>()
20526                .as_slice(),
20527            *result,
20528        );
20529    }
20530}
20531
20532fn wrap_with_prefix(
20533    line_prefix: String,
20534    unwrapped_text: String,
20535    wrap_column: usize,
20536    tab_size: NonZeroU32,
20537    preserve_existing_whitespace: bool,
20538) -> String {
20539    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20540    let mut wrapped_text = String::new();
20541    let mut current_line = line_prefix.clone();
20542
20543    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20544    let mut current_line_len = line_prefix_len;
20545    let mut in_whitespace = false;
20546    for token in tokenizer {
20547        let have_preceding_whitespace = in_whitespace;
20548        match token {
20549            WordBreakToken::Word {
20550                token,
20551                grapheme_len,
20552            } => {
20553                in_whitespace = false;
20554                if current_line_len + grapheme_len > wrap_column
20555                    && current_line_len != line_prefix_len
20556                {
20557                    wrapped_text.push_str(current_line.trim_end());
20558                    wrapped_text.push('\n');
20559                    current_line.truncate(line_prefix.len());
20560                    current_line_len = line_prefix_len;
20561                }
20562                current_line.push_str(token);
20563                current_line_len += grapheme_len;
20564            }
20565            WordBreakToken::InlineWhitespace {
20566                mut token,
20567                mut grapheme_len,
20568            } => {
20569                in_whitespace = true;
20570                if have_preceding_whitespace && !preserve_existing_whitespace {
20571                    continue;
20572                }
20573                if !preserve_existing_whitespace {
20574                    token = " ";
20575                    grapheme_len = 1;
20576                }
20577                if current_line_len + grapheme_len > wrap_column {
20578                    wrapped_text.push_str(current_line.trim_end());
20579                    wrapped_text.push('\n');
20580                    current_line.truncate(line_prefix.len());
20581                    current_line_len = line_prefix_len;
20582                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20583                    current_line.push_str(token);
20584                    current_line_len += grapheme_len;
20585                }
20586            }
20587            WordBreakToken::Newline => {
20588                in_whitespace = true;
20589                if preserve_existing_whitespace {
20590                    wrapped_text.push_str(current_line.trim_end());
20591                    wrapped_text.push('\n');
20592                    current_line.truncate(line_prefix.len());
20593                    current_line_len = line_prefix_len;
20594                } else if have_preceding_whitespace {
20595                    continue;
20596                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20597                {
20598                    wrapped_text.push_str(current_line.trim_end());
20599                    wrapped_text.push('\n');
20600                    current_line.truncate(line_prefix.len());
20601                    current_line_len = line_prefix_len;
20602                } else if current_line_len != line_prefix_len {
20603                    current_line.push(' ');
20604                    current_line_len += 1;
20605                }
20606            }
20607        }
20608    }
20609
20610    if !current_line.is_empty() {
20611        wrapped_text.push_str(&current_line);
20612    }
20613    wrapped_text
20614}
20615
20616#[test]
20617fn test_wrap_with_prefix() {
20618    assert_eq!(
20619        wrap_with_prefix(
20620            "# ".to_string(),
20621            "abcdefg".to_string(),
20622            4,
20623            NonZeroU32::new(4).unwrap(),
20624            false,
20625        ),
20626        "# abcdefg"
20627    );
20628    assert_eq!(
20629        wrap_with_prefix(
20630            "".to_string(),
20631            "\thello world".to_string(),
20632            8,
20633            NonZeroU32::new(4).unwrap(),
20634            false,
20635        ),
20636        "hello\nworld"
20637    );
20638    assert_eq!(
20639        wrap_with_prefix(
20640            "// ".to_string(),
20641            "xx \nyy zz aa bb cc".to_string(),
20642            12,
20643            NonZeroU32::new(4).unwrap(),
20644            false,
20645        ),
20646        "// xx yy zz\n// aa bb cc"
20647    );
20648    assert_eq!(
20649        wrap_with_prefix(
20650            String::new(),
20651            "这是什么 \n 钢笔".to_string(),
20652            3,
20653            NonZeroU32::new(4).unwrap(),
20654            false,
20655        ),
20656        "这是什\n么 钢\n"
20657    );
20658}
20659
20660pub trait CollaborationHub {
20661    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20662    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20663    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20664}
20665
20666impl CollaborationHub for Entity<Project> {
20667    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20668        self.read(cx).collaborators()
20669    }
20670
20671    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20672        self.read(cx).user_store().read(cx).participant_indices()
20673    }
20674
20675    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20676        let this = self.read(cx);
20677        let user_ids = this.collaborators().values().map(|c| c.user_id);
20678        this.user_store().read(cx).participant_names(user_ids, cx)
20679    }
20680}
20681
20682pub trait SemanticsProvider {
20683    fn hover(
20684        &self,
20685        buffer: &Entity<Buffer>,
20686        position: text::Anchor,
20687        cx: &mut App,
20688    ) -> Option<Task<Vec<project::Hover>>>;
20689
20690    fn inline_values(
20691        &self,
20692        buffer_handle: Entity<Buffer>,
20693        range: Range<text::Anchor>,
20694        cx: &mut App,
20695    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20696
20697    fn inlay_hints(
20698        &self,
20699        buffer_handle: Entity<Buffer>,
20700        range: Range<text::Anchor>,
20701        cx: &mut App,
20702    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20703
20704    fn resolve_inlay_hint(
20705        &self,
20706        hint: InlayHint,
20707        buffer_handle: Entity<Buffer>,
20708        server_id: LanguageServerId,
20709        cx: &mut App,
20710    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20711
20712    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20713
20714    fn document_highlights(
20715        &self,
20716        buffer: &Entity<Buffer>,
20717        position: text::Anchor,
20718        cx: &mut App,
20719    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20720
20721    fn definitions(
20722        &self,
20723        buffer: &Entity<Buffer>,
20724        position: text::Anchor,
20725        kind: GotoDefinitionKind,
20726        cx: &mut App,
20727    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20728
20729    fn range_for_rename(
20730        &self,
20731        buffer: &Entity<Buffer>,
20732        position: text::Anchor,
20733        cx: &mut App,
20734    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20735
20736    fn perform_rename(
20737        &self,
20738        buffer: &Entity<Buffer>,
20739        position: text::Anchor,
20740        new_name: String,
20741        cx: &mut App,
20742    ) -> Option<Task<Result<ProjectTransaction>>>;
20743
20744    fn pull_diagnostics_for_buffer(
20745        &self,
20746        buffer: Entity<Buffer>,
20747        cx: &mut App,
20748    ) -> Task<anyhow::Result<()>>;
20749}
20750
20751pub trait CompletionProvider {
20752    fn completions(
20753        &self,
20754        excerpt_id: ExcerptId,
20755        buffer: &Entity<Buffer>,
20756        buffer_position: text::Anchor,
20757        trigger: CompletionContext,
20758        window: &mut Window,
20759        cx: &mut Context<Editor>,
20760    ) -> Task<Result<Vec<CompletionResponse>>>;
20761
20762    fn resolve_completions(
20763        &self,
20764        _buffer: Entity<Buffer>,
20765        _completion_indices: Vec<usize>,
20766        _completions: Rc<RefCell<Box<[Completion]>>>,
20767        _cx: &mut Context<Editor>,
20768    ) -> Task<Result<bool>> {
20769        Task::ready(Ok(false))
20770    }
20771
20772    fn apply_additional_edits_for_completion(
20773        &self,
20774        _buffer: Entity<Buffer>,
20775        _completions: Rc<RefCell<Box<[Completion]>>>,
20776        _completion_index: usize,
20777        _push_to_history: bool,
20778        _cx: &mut Context<Editor>,
20779    ) -> Task<Result<Option<language::Transaction>>> {
20780        Task::ready(Ok(None))
20781    }
20782
20783    fn is_completion_trigger(
20784        &self,
20785        buffer: &Entity<Buffer>,
20786        position: language::Anchor,
20787        text: &str,
20788        trigger_in_words: bool,
20789        menu_is_open: bool,
20790        cx: &mut Context<Editor>,
20791    ) -> bool;
20792
20793    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20794
20795    fn sort_completions(&self) -> bool {
20796        true
20797    }
20798
20799    fn filter_completions(&self) -> bool {
20800        true
20801    }
20802}
20803
20804pub trait CodeActionProvider {
20805    fn id(&self) -> Arc<str>;
20806
20807    fn code_actions(
20808        &self,
20809        buffer: &Entity<Buffer>,
20810        range: Range<text::Anchor>,
20811        window: &mut Window,
20812        cx: &mut App,
20813    ) -> Task<Result<Vec<CodeAction>>>;
20814
20815    fn apply_code_action(
20816        &self,
20817        buffer_handle: Entity<Buffer>,
20818        action: CodeAction,
20819        excerpt_id: ExcerptId,
20820        push_to_history: bool,
20821        window: &mut Window,
20822        cx: &mut App,
20823    ) -> Task<Result<ProjectTransaction>>;
20824}
20825
20826impl CodeActionProvider for Entity<Project> {
20827    fn id(&self) -> Arc<str> {
20828        "project".into()
20829    }
20830
20831    fn code_actions(
20832        &self,
20833        buffer: &Entity<Buffer>,
20834        range: Range<text::Anchor>,
20835        _window: &mut Window,
20836        cx: &mut App,
20837    ) -> Task<Result<Vec<CodeAction>>> {
20838        self.update(cx, |project, cx| {
20839            let code_lens = project.code_lens(buffer, range.clone(), cx);
20840            let code_actions = project.code_actions(buffer, range, None, cx);
20841            cx.background_spawn(async move {
20842                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20843                Ok(code_lens
20844                    .context("code lens fetch")?
20845                    .into_iter()
20846                    .chain(code_actions.context("code action fetch")?)
20847                    .collect())
20848            })
20849        })
20850    }
20851
20852    fn apply_code_action(
20853        &self,
20854        buffer_handle: Entity<Buffer>,
20855        action: CodeAction,
20856        _excerpt_id: ExcerptId,
20857        push_to_history: bool,
20858        _window: &mut Window,
20859        cx: &mut App,
20860    ) -> Task<Result<ProjectTransaction>> {
20861        self.update(cx, |project, cx| {
20862            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20863        })
20864    }
20865}
20866
20867fn snippet_completions(
20868    project: &Project,
20869    buffer: &Entity<Buffer>,
20870    buffer_position: text::Anchor,
20871    cx: &mut App,
20872) -> Task<Result<CompletionResponse>> {
20873    let languages = buffer.read(cx).languages_at(buffer_position);
20874    let snippet_store = project.snippets().read(cx);
20875
20876    let scopes: Vec<_> = languages
20877        .iter()
20878        .filter_map(|language| {
20879            let language_name = language.lsp_id();
20880            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20881
20882            if snippets.is_empty() {
20883                None
20884            } else {
20885                Some((language.default_scope(), snippets))
20886            }
20887        })
20888        .collect();
20889
20890    if scopes.is_empty() {
20891        return Task::ready(Ok(CompletionResponse {
20892            completions: vec![],
20893            is_incomplete: false,
20894        }));
20895    }
20896
20897    let snapshot = buffer.read(cx).text_snapshot();
20898    let chars: String = snapshot
20899        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20900        .collect();
20901    let executor = cx.background_executor().clone();
20902
20903    cx.background_spawn(async move {
20904        let mut is_incomplete = false;
20905        let mut completions: Vec<Completion> = Vec::new();
20906        for (scope, snippets) in scopes.into_iter() {
20907            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20908            let mut last_word = chars
20909                .chars()
20910                .take_while(|c| classifier.is_word(*c))
20911                .collect::<String>();
20912            last_word = last_word.chars().rev().collect();
20913
20914            if last_word.is_empty() {
20915                return Ok(CompletionResponse {
20916                    completions: vec![],
20917                    is_incomplete: true,
20918                });
20919            }
20920
20921            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20922            let to_lsp = |point: &text::Anchor| {
20923                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20924                point_to_lsp(end)
20925            };
20926            let lsp_end = to_lsp(&buffer_position);
20927
20928            let candidates = snippets
20929                .iter()
20930                .enumerate()
20931                .flat_map(|(ix, snippet)| {
20932                    snippet
20933                        .prefix
20934                        .iter()
20935                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20936                })
20937                .collect::<Vec<StringMatchCandidate>>();
20938
20939            const MAX_RESULTS: usize = 100;
20940            let mut matches = fuzzy::match_strings(
20941                &candidates,
20942                &last_word,
20943                last_word.chars().any(|c| c.is_uppercase()),
20944                MAX_RESULTS,
20945                &Default::default(),
20946                executor.clone(),
20947            )
20948            .await;
20949
20950            if matches.len() >= MAX_RESULTS {
20951                is_incomplete = true;
20952            }
20953
20954            // Remove all candidates where the query's start does not match the start of any word in the candidate
20955            if let Some(query_start) = last_word.chars().next() {
20956                matches.retain(|string_match| {
20957                    split_words(&string_match.string).any(|word| {
20958                        // Check that the first codepoint of the word as lowercase matches the first
20959                        // codepoint of the query as lowercase
20960                        word.chars()
20961                            .flat_map(|codepoint| codepoint.to_lowercase())
20962                            .zip(query_start.to_lowercase())
20963                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20964                    })
20965                });
20966            }
20967
20968            let matched_strings = matches
20969                .into_iter()
20970                .map(|m| m.string)
20971                .collect::<HashSet<_>>();
20972
20973            completions.extend(snippets.iter().filter_map(|snippet| {
20974                let matching_prefix = snippet
20975                    .prefix
20976                    .iter()
20977                    .find(|prefix| matched_strings.contains(*prefix))?;
20978                let start = as_offset - last_word.len();
20979                let start = snapshot.anchor_before(start);
20980                let range = start..buffer_position;
20981                let lsp_start = to_lsp(&start);
20982                let lsp_range = lsp::Range {
20983                    start: lsp_start,
20984                    end: lsp_end,
20985                };
20986                Some(Completion {
20987                    replace_range: range,
20988                    new_text: snippet.body.clone(),
20989                    source: CompletionSource::Lsp {
20990                        insert_range: None,
20991                        server_id: LanguageServerId(usize::MAX),
20992                        resolved: true,
20993                        lsp_completion: Box::new(lsp::CompletionItem {
20994                            label: snippet.prefix.first().unwrap().clone(),
20995                            kind: Some(CompletionItemKind::SNIPPET),
20996                            label_details: snippet.description.as_ref().map(|description| {
20997                                lsp::CompletionItemLabelDetails {
20998                                    detail: Some(description.clone()),
20999                                    description: None,
21000                                }
21001                            }),
21002                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21003                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21004                                lsp::InsertReplaceEdit {
21005                                    new_text: snippet.body.clone(),
21006                                    insert: lsp_range,
21007                                    replace: lsp_range,
21008                                },
21009                            )),
21010                            filter_text: Some(snippet.body.clone()),
21011                            sort_text: Some(char::MAX.to_string()),
21012                            ..lsp::CompletionItem::default()
21013                        }),
21014                        lsp_defaults: None,
21015                    },
21016                    label: CodeLabel {
21017                        text: matching_prefix.clone(),
21018                        runs: Vec::new(),
21019                        filter_range: 0..matching_prefix.len(),
21020                    },
21021                    icon_path: None,
21022                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21023                        single_line: snippet.name.clone().into(),
21024                        plain_text: snippet
21025                            .description
21026                            .clone()
21027                            .map(|description| description.into()),
21028                    }),
21029                    insert_text_mode: None,
21030                    confirm: None,
21031                })
21032            }))
21033        }
21034
21035        Ok(CompletionResponse {
21036            completions,
21037            is_incomplete,
21038        })
21039    })
21040}
21041
21042impl CompletionProvider for Entity<Project> {
21043    fn completions(
21044        &self,
21045        _excerpt_id: ExcerptId,
21046        buffer: &Entity<Buffer>,
21047        buffer_position: text::Anchor,
21048        options: CompletionContext,
21049        _window: &mut Window,
21050        cx: &mut Context<Editor>,
21051    ) -> Task<Result<Vec<CompletionResponse>>> {
21052        self.update(cx, |project, cx| {
21053            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21054            let project_completions = project.completions(buffer, buffer_position, options, cx);
21055            cx.background_spawn(async move {
21056                let mut responses = project_completions.await?;
21057                let snippets = snippets.await?;
21058                if !snippets.completions.is_empty() {
21059                    responses.push(snippets);
21060                }
21061                Ok(responses)
21062            })
21063        })
21064    }
21065
21066    fn resolve_completions(
21067        &self,
21068        buffer: Entity<Buffer>,
21069        completion_indices: Vec<usize>,
21070        completions: Rc<RefCell<Box<[Completion]>>>,
21071        cx: &mut Context<Editor>,
21072    ) -> Task<Result<bool>> {
21073        self.update(cx, |project, cx| {
21074            project.lsp_store().update(cx, |lsp_store, cx| {
21075                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21076            })
21077        })
21078    }
21079
21080    fn apply_additional_edits_for_completion(
21081        &self,
21082        buffer: Entity<Buffer>,
21083        completions: Rc<RefCell<Box<[Completion]>>>,
21084        completion_index: usize,
21085        push_to_history: bool,
21086        cx: &mut Context<Editor>,
21087    ) -> Task<Result<Option<language::Transaction>>> {
21088        self.update(cx, |project, cx| {
21089            project.lsp_store().update(cx, |lsp_store, cx| {
21090                lsp_store.apply_additional_edits_for_completion(
21091                    buffer,
21092                    completions,
21093                    completion_index,
21094                    push_to_history,
21095                    cx,
21096                )
21097            })
21098        })
21099    }
21100
21101    fn is_completion_trigger(
21102        &self,
21103        buffer: &Entity<Buffer>,
21104        position: language::Anchor,
21105        text: &str,
21106        trigger_in_words: bool,
21107        menu_is_open: bool,
21108        cx: &mut Context<Editor>,
21109    ) -> bool {
21110        let mut chars = text.chars();
21111        let char = if let Some(char) = chars.next() {
21112            char
21113        } else {
21114            return false;
21115        };
21116        if chars.next().is_some() {
21117            return false;
21118        }
21119
21120        let buffer = buffer.read(cx);
21121        let snapshot = buffer.snapshot();
21122        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21123            return false;
21124        }
21125        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21126        if trigger_in_words && classifier.is_word(char) {
21127            return true;
21128        }
21129
21130        buffer.completion_triggers().contains(text)
21131    }
21132}
21133
21134impl SemanticsProvider for Entity<Project> {
21135    fn hover(
21136        &self,
21137        buffer: &Entity<Buffer>,
21138        position: text::Anchor,
21139        cx: &mut App,
21140    ) -> Option<Task<Vec<project::Hover>>> {
21141        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21142    }
21143
21144    fn document_highlights(
21145        &self,
21146        buffer: &Entity<Buffer>,
21147        position: text::Anchor,
21148        cx: &mut App,
21149    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21150        Some(self.update(cx, |project, cx| {
21151            project.document_highlights(buffer, position, cx)
21152        }))
21153    }
21154
21155    fn definitions(
21156        &self,
21157        buffer: &Entity<Buffer>,
21158        position: text::Anchor,
21159        kind: GotoDefinitionKind,
21160        cx: &mut App,
21161    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21162        Some(self.update(cx, |project, cx| match kind {
21163            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21164            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21165            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21166            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21167        }))
21168    }
21169
21170    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21171        // TODO: make this work for remote projects
21172        self.update(cx, |project, cx| {
21173            if project
21174                .active_debug_session(cx)
21175                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21176            {
21177                return true;
21178            }
21179
21180            buffer.update(cx, |buffer, cx| {
21181                project.any_language_server_supports_inlay_hints(buffer, cx)
21182            })
21183        })
21184    }
21185
21186    fn inline_values(
21187        &self,
21188        buffer_handle: Entity<Buffer>,
21189
21190        range: Range<text::Anchor>,
21191        cx: &mut App,
21192    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21193        self.update(cx, |project, cx| {
21194            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21195
21196            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21197        })
21198    }
21199
21200    fn inlay_hints(
21201        &self,
21202        buffer_handle: Entity<Buffer>,
21203        range: Range<text::Anchor>,
21204        cx: &mut App,
21205    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21206        Some(self.update(cx, |project, cx| {
21207            project.inlay_hints(buffer_handle, range, cx)
21208        }))
21209    }
21210
21211    fn resolve_inlay_hint(
21212        &self,
21213        hint: InlayHint,
21214        buffer_handle: Entity<Buffer>,
21215        server_id: LanguageServerId,
21216        cx: &mut App,
21217    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21218        Some(self.update(cx, |project, cx| {
21219            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21220        }))
21221    }
21222
21223    fn range_for_rename(
21224        &self,
21225        buffer: &Entity<Buffer>,
21226        position: text::Anchor,
21227        cx: &mut App,
21228    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21229        Some(self.update(cx, |project, cx| {
21230            let buffer = buffer.clone();
21231            let task = project.prepare_rename(buffer.clone(), position, cx);
21232            cx.spawn(async move |_, cx| {
21233                Ok(match task.await? {
21234                    PrepareRenameResponse::Success(range) => Some(range),
21235                    PrepareRenameResponse::InvalidPosition => None,
21236                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21237                        // Fallback on using TreeSitter info to determine identifier range
21238                        buffer.read_with(cx, |buffer, _| {
21239                            let snapshot = buffer.snapshot();
21240                            let (range, kind) = snapshot.surrounding_word(position);
21241                            if kind != Some(CharKind::Word) {
21242                                return None;
21243                            }
21244                            Some(
21245                                snapshot.anchor_before(range.start)
21246                                    ..snapshot.anchor_after(range.end),
21247                            )
21248                        })?
21249                    }
21250                })
21251            })
21252        }))
21253    }
21254
21255    fn perform_rename(
21256        &self,
21257        buffer: &Entity<Buffer>,
21258        position: text::Anchor,
21259        new_name: String,
21260        cx: &mut App,
21261    ) -> Option<Task<Result<ProjectTransaction>>> {
21262        Some(self.update(cx, |project, cx| {
21263            project.perform_rename(buffer.clone(), position, new_name, cx)
21264        }))
21265    }
21266
21267    fn pull_diagnostics_for_buffer(
21268        &self,
21269        buffer: Entity<Buffer>,
21270        cx: &mut App,
21271    ) -> Task<anyhow::Result<()>> {
21272        let diagnostics = self.update(cx, |project, cx| {
21273            project
21274                .lsp_store()
21275                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21276        });
21277        let project = self.clone();
21278        cx.spawn(async move |cx| {
21279            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21280            project.update(cx, |project, cx| {
21281                project.lsp_store().update(cx, |lsp_store, cx| {
21282                    for diagnostics_set in diagnostics {
21283                        let LspPullDiagnostics::Response {
21284                            server_id,
21285                            uri,
21286                            diagnostics,
21287                        } = diagnostics_set
21288                        else {
21289                            continue;
21290                        };
21291
21292                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21293                        let disk_based_sources = adapter
21294                            .as_ref()
21295                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21296                            .unwrap_or(&[]);
21297                        match diagnostics {
21298                            PulledDiagnostics::Unchanged { result_id } => {
21299                                lsp_store
21300                                    .merge_diagnostics(
21301                                        server_id,
21302                                        lsp::PublishDiagnosticsParams {
21303                                            uri: uri.clone(),
21304                                            diagnostics: Vec::new(),
21305                                            version: None,
21306                                        },
21307                                        Some(result_id),
21308                                        DiagnosticSourceKind::Pulled,
21309                                        disk_based_sources,
21310                                        |_, _| true,
21311                                        cx,
21312                                    )
21313                                    .log_err();
21314                            }
21315                            PulledDiagnostics::Changed {
21316                                diagnostics,
21317                                result_id,
21318                            } => {
21319                                lsp_store
21320                                    .merge_diagnostics(
21321                                        server_id,
21322                                        lsp::PublishDiagnosticsParams {
21323                                            uri: uri.clone(),
21324                                            diagnostics,
21325                                            version: None,
21326                                        },
21327                                        result_id,
21328                                        DiagnosticSourceKind::Pulled,
21329                                        disk_based_sources,
21330                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21331                                            DiagnosticSourceKind::Pulled => false,
21332                                            DiagnosticSourceKind::Other
21333                                            | DiagnosticSourceKind::Pushed => true,
21334                                        },
21335                                        cx,
21336                                    )
21337                                    .log_err();
21338                            }
21339                        }
21340                    }
21341                })
21342            })
21343        })
21344    }
21345}
21346
21347fn inlay_hint_settings(
21348    location: Anchor,
21349    snapshot: &MultiBufferSnapshot,
21350    cx: &mut Context<Editor>,
21351) -> InlayHintSettings {
21352    let file = snapshot.file_at(location);
21353    let language = snapshot.language_at(location).map(|l| l.name());
21354    language_settings(language, file, cx).inlay_hints
21355}
21356
21357fn consume_contiguous_rows(
21358    contiguous_row_selections: &mut Vec<Selection<Point>>,
21359    selection: &Selection<Point>,
21360    display_map: &DisplaySnapshot,
21361    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21362) -> (MultiBufferRow, MultiBufferRow) {
21363    contiguous_row_selections.push(selection.clone());
21364    let start_row = MultiBufferRow(selection.start.row);
21365    let mut end_row = ending_row(selection, display_map);
21366
21367    while let Some(next_selection) = selections.peek() {
21368        if next_selection.start.row <= end_row.0 {
21369            end_row = ending_row(next_selection, display_map);
21370            contiguous_row_selections.push(selections.next().unwrap().clone());
21371        } else {
21372            break;
21373        }
21374    }
21375    (start_row, end_row)
21376}
21377
21378fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21379    if next_selection.end.column > 0 || next_selection.is_empty() {
21380        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21381    } else {
21382        MultiBufferRow(next_selection.end.row)
21383    }
21384}
21385
21386impl EditorSnapshot {
21387    pub fn remote_selections_in_range<'a>(
21388        &'a self,
21389        range: &'a Range<Anchor>,
21390        collaboration_hub: &dyn CollaborationHub,
21391        cx: &'a App,
21392    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21393        let participant_names = collaboration_hub.user_names(cx);
21394        let participant_indices = collaboration_hub.user_participant_indices(cx);
21395        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21396        let collaborators_by_replica_id = collaborators_by_peer_id
21397            .values()
21398            .map(|collaborator| (collaborator.replica_id, collaborator))
21399            .collect::<HashMap<_, _>>();
21400        self.buffer_snapshot
21401            .selections_in_range(range, false)
21402            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21403                if replica_id == AGENT_REPLICA_ID {
21404                    Some(RemoteSelection {
21405                        replica_id,
21406                        selection,
21407                        cursor_shape,
21408                        line_mode,
21409                        collaborator_id: CollaboratorId::Agent,
21410                        user_name: Some("Agent".into()),
21411                        color: cx.theme().players().agent(),
21412                    })
21413                } else {
21414                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21415                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21416                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21417                    Some(RemoteSelection {
21418                        replica_id,
21419                        selection,
21420                        cursor_shape,
21421                        line_mode,
21422                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21423                        user_name,
21424                        color: if let Some(index) = participant_index {
21425                            cx.theme().players().color_for_participant(index.0)
21426                        } else {
21427                            cx.theme().players().absent()
21428                        },
21429                    })
21430                }
21431            })
21432    }
21433
21434    pub fn hunks_for_ranges(
21435        &self,
21436        ranges: impl IntoIterator<Item = Range<Point>>,
21437    ) -> Vec<MultiBufferDiffHunk> {
21438        let mut hunks = Vec::new();
21439        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21440            HashMap::default();
21441        for query_range in ranges {
21442            let query_rows =
21443                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21444            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21445                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21446            ) {
21447                // Include deleted hunks that are adjacent to the query range, because
21448                // otherwise they would be missed.
21449                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21450                if hunk.status().is_deleted() {
21451                    intersects_range |= hunk.row_range.start == query_rows.end;
21452                    intersects_range |= hunk.row_range.end == query_rows.start;
21453                }
21454                if intersects_range {
21455                    if !processed_buffer_rows
21456                        .entry(hunk.buffer_id)
21457                        .or_default()
21458                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21459                    {
21460                        continue;
21461                    }
21462                    hunks.push(hunk);
21463                }
21464            }
21465        }
21466
21467        hunks
21468    }
21469
21470    fn display_diff_hunks_for_rows<'a>(
21471        &'a self,
21472        display_rows: Range<DisplayRow>,
21473        folded_buffers: &'a HashSet<BufferId>,
21474    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21475        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21476        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21477
21478        self.buffer_snapshot
21479            .diff_hunks_in_range(buffer_start..buffer_end)
21480            .filter_map(|hunk| {
21481                if folded_buffers.contains(&hunk.buffer_id) {
21482                    return None;
21483                }
21484
21485                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21486                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21487
21488                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21489                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21490
21491                let display_hunk = if hunk_display_start.column() != 0 {
21492                    DisplayDiffHunk::Folded {
21493                        display_row: hunk_display_start.row(),
21494                    }
21495                } else {
21496                    let mut end_row = hunk_display_end.row();
21497                    if hunk_display_end.column() > 0 {
21498                        end_row.0 += 1;
21499                    }
21500                    let is_created_file = hunk.is_created_file();
21501                    DisplayDiffHunk::Unfolded {
21502                        status: hunk.status(),
21503                        diff_base_byte_range: hunk.diff_base_byte_range,
21504                        display_row_range: hunk_display_start.row()..end_row,
21505                        multi_buffer_range: Anchor::range_in_buffer(
21506                            hunk.excerpt_id,
21507                            hunk.buffer_id,
21508                            hunk.buffer_range,
21509                        ),
21510                        is_created_file,
21511                    }
21512                };
21513
21514                Some(display_hunk)
21515            })
21516    }
21517
21518    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21519        self.display_snapshot.buffer_snapshot.language_at(position)
21520    }
21521
21522    pub fn is_focused(&self) -> bool {
21523        self.is_focused
21524    }
21525
21526    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21527        self.placeholder_text.as_ref()
21528    }
21529
21530    pub fn scroll_position(&self) -> gpui::Point<f32> {
21531        self.scroll_anchor.scroll_position(&self.display_snapshot)
21532    }
21533
21534    fn gutter_dimensions(
21535        &self,
21536        font_id: FontId,
21537        font_size: Pixels,
21538        max_line_number_width: Pixels,
21539        cx: &App,
21540    ) -> Option<GutterDimensions> {
21541        if !self.show_gutter {
21542            return None;
21543        }
21544
21545        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21546        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21547
21548        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21549            matches!(
21550                ProjectSettings::get_global(cx).git.git_gutter,
21551                Some(GitGutterSetting::TrackedFiles)
21552            )
21553        });
21554        let gutter_settings = EditorSettings::get_global(cx).gutter;
21555        let show_line_numbers = self
21556            .show_line_numbers
21557            .unwrap_or(gutter_settings.line_numbers);
21558        let line_gutter_width = if show_line_numbers {
21559            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21560            let min_width_for_number_on_gutter =
21561                em_advance * gutter_settings.min_line_number_digits as f32;
21562            max_line_number_width.max(min_width_for_number_on_gutter)
21563        } else {
21564            0.0.into()
21565        };
21566
21567        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21568        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21569
21570        let git_blame_entries_width =
21571            self.git_blame_gutter_max_author_length
21572                .map(|max_author_length| {
21573                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21574                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21575
21576                    /// The number of characters to dedicate to gaps and margins.
21577                    const SPACING_WIDTH: usize = 4;
21578
21579                    let max_char_count = max_author_length.min(renderer.max_author_length())
21580                        + ::git::SHORT_SHA_LENGTH
21581                        + MAX_RELATIVE_TIMESTAMP.len()
21582                        + SPACING_WIDTH;
21583
21584                    em_advance * max_char_count
21585                });
21586
21587        let is_singleton = self.buffer_snapshot.is_singleton();
21588
21589        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21590        left_padding += if !is_singleton {
21591            em_width * 4.0
21592        } else if show_runnables || show_breakpoints {
21593            em_width * 3.0
21594        } else if show_git_gutter && show_line_numbers {
21595            em_width * 2.0
21596        } else if show_git_gutter || show_line_numbers {
21597            em_width
21598        } else {
21599            px(0.)
21600        };
21601
21602        let shows_folds = is_singleton && gutter_settings.folds;
21603
21604        let right_padding = if shows_folds && show_line_numbers {
21605            em_width * 4.0
21606        } else if shows_folds || (!is_singleton && show_line_numbers) {
21607            em_width * 3.0
21608        } else if show_line_numbers {
21609            em_width
21610        } else {
21611            px(0.)
21612        };
21613
21614        Some(GutterDimensions {
21615            left_padding,
21616            right_padding,
21617            width: line_gutter_width + left_padding + right_padding,
21618            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21619            git_blame_entries_width,
21620        })
21621    }
21622
21623    pub fn render_crease_toggle(
21624        &self,
21625        buffer_row: MultiBufferRow,
21626        row_contains_cursor: bool,
21627        editor: Entity<Editor>,
21628        window: &mut Window,
21629        cx: &mut App,
21630    ) -> Option<AnyElement> {
21631        let folded = self.is_line_folded(buffer_row);
21632        let mut is_foldable = false;
21633
21634        if let Some(crease) = self
21635            .crease_snapshot
21636            .query_row(buffer_row, &self.buffer_snapshot)
21637        {
21638            is_foldable = true;
21639            match crease {
21640                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21641                    if let Some(render_toggle) = render_toggle {
21642                        let toggle_callback =
21643                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21644                                if folded {
21645                                    editor.update(cx, |editor, cx| {
21646                                        editor.fold_at(buffer_row, window, cx)
21647                                    });
21648                                } else {
21649                                    editor.update(cx, |editor, cx| {
21650                                        editor.unfold_at(buffer_row, window, cx)
21651                                    });
21652                                }
21653                            });
21654                        return Some((render_toggle)(
21655                            buffer_row,
21656                            folded,
21657                            toggle_callback,
21658                            window,
21659                            cx,
21660                        ));
21661                    }
21662                }
21663            }
21664        }
21665
21666        is_foldable |= self.starts_indent(buffer_row);
21667
21668        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21669            Some(
21670                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21671                    .toggle_state(folded)
21672                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21673                        if folded {
21674                            this.unfold_at(buffer_row, window, cx);
21675                        } else {
21676                            this.fold_at(buffer_row, window, cx);
21677                        }
21678                    }))
21679                    .into_any_element(),
21680            )
21681        } else {
21682            None
21683        }
21684    }
21685
21686    pub fn render_crease_trailer(
21687        &self,
21688        buffer_row: MultiBufferRow,
21689        window: &mut Window,
21690        cx: &mut App,
21691    ) -> Option<AnyElement> {
21692        let folded = self.is_line_folded(buffer_row);
21693        if let Crease::Inline { render_trailer, .. } = self
21694            .crease_snapshot
21695            .query_row(buffer_row, &self.buffer_snapshot)?
21696        {
21697            let render_trailer = render_trailer.as_ref()?;
21698            Some(render_trailer(buffer_row, folded, window, cx))
21699        } else {
21700            None
21701        }
21702    }
21703}
21704
21705impl Deref for EditorSnapshot {
21706    type Target = DisplaySnapshot;
21707
21708    fn deref(&self) -> &Self::Target {
21709        &self.display_snapshot
21710    }
21711}
21712
21713#[derive(Clone, Debug, PartialEq, Eq)]
21714pub enum EditorEvent {
21715    InputIgnored {
21716        text: Arc<str>,
21717    },
21718    InputHandled {
21719        utf16_range_to_replace: Option<Range<isize>>,
21720        text: Arc<str>,
21721    },
21722    ExcerptsAdded {
21723        buffer: Entity<Buffer>,
21724        predecessor: ExcerptId,
21725        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21726    },
21727    ExcerptsRemoved {
21728        ids: Vec<ExcerptId>,
21729        removed_buffer_ids: Vec<BufferId>,
21730    },
21731    BufferFoldToggled {
21732        ids: Vec<ExcerptId>,
21733        folded: bool,
21734    },
21735    ExcerptsEdited {
21736        ids: Vec<ExcerptId>,
21737    },
21738    ExcerptsExpanded {
21739        ids: Vec<ExcerptId>,
21740    },
21741    BufferEdited,
21742    Edited {
21743        transaction_id: clock::Lamport,
21744    },
21745    Reparsed(BufferId),
21746    Focused,
21747    FocusedIn,
21748    Blurred,
21749    DirtyChanged,
21750    Saved,
21751    TitleChanged,
21752    DiffBaseChanged,
21753    SelectionsChanged {
21754        local: bool,
21755    },
21756    ScrollPositionChanged {
21757        local: bool,
21758        autoscroll: bool,
21759    },
21760    Closed,
21761    TransactionUndone {
21762        transaction_id: clock::Lamport,
21763    },
21764    TransactionBegun {
21765        transaction_id: clock::Lamport,
21766    },
21767    Reloaded,
21768    CursorShapeChanged,
21769    PushedToNavHistory {
21770        anchor: Anchor,
21771        is_deactivate: bool,
21772    },
21773}
21774
21775impl EventEmitter<EditorEvent> for Editor {}
21776
21777impl Focusable for Editor {
21778    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21779        self.focus_handle.clone()
21780    }
21781}
21782
21783impl Render for Editor {
21784    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21785        let settings = ThemeSettings::get_global(cx);
21786
21787        let mut text_style = match self.mode {
21788            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21789                color: cx.theme().colors().editor_foreground,
21790                font_family: settings.ui_font.family.clone(),
21791                font_features: settings.ui_font.features.clone(),
21792                font_fallbacks: settings.ui_font.fallbacks.clone(),
21793                font_size: rems(0.875).into(),
21794                font_weight: settings.ui_font.weight,
21795                line_height: relative(settings.buffer_line_height.value()),
21796                ..Default::default()
21797            },
21798            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21799                color: cx.theme().colors().editor_foreground,
21800                font_family: settings.buffer_font.family.clone(),
21801                font_features: settings.buffer_font.features.clone(),
21802                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21803                font_size: settings.buffer_font_size(cx).into(),
21804                font_weight: settings.buffer_font.weight,
21805                line_height: relative(settings.buffer_line_height.value()),
21806                ..Default::default()
21807            },
21808        };
21809        if let Some(text_style_refinement) = &self.text_style_refinement {
21810            text_style.refine(text_style_refinement)
21811        }
21812
21813        let background = match self.mode {
21814            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21815            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21816            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21817            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21818        };
21819
21820        EditorElement::new(
21821            &cx.entity(),
21822            EditorStyle {
21823                background,
21824                local_player: cx.theme().players().local(),
21825                text: text_style,
21826                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21827                syntax: cx.theme().syntax().clone(),
21828                status: cx.theme().status().clone(),
21829                inlay_hints_style: make_inlay_hints_style(cx),
21830                inline_completion_styles: make_suggestion_styles(cx),
21831                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21832                show_underlines: !self.mode.is_minimap(),
21833            },
21834        )
21835    }
21836}
21837
21838impl EntityInputHandler for Editor {
21839    fn text_for_range(
21840        &mut self,
21841        range_utf16: Range<usize>,
21842        adjusted_range: &mut Option<Range<usize>>,
21843        _: &mut Window,
21844        cx: &mut Context<Self>,
21845    ) -> Option<String> {
21846        let snapshot = self.buffer.read(cx).read(cx);
21847        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21848        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21849        if (start.0..end.0) != range_utf16 {
21850            adjusted_range.replace(start.0..end.0);
21851        }
21852        Some(snapshot.text_for_range(start..end).collect())
21853    }
21854
21855    fn selected_text_range(
21856        &mut self,
21857        ignore_disabled_input: bool,
21858        _: &mut Window,
21859        cx: &mut Context<Self>,
21860    ) -> Option<UTF16Selection> {
21861        // Prevent the IME menu from appearing when holding down an alphabetic key
21862        // while input is disabled.
21863        if !ignore_disabled_input && !self.input_enabled {
21864            return None;
21865        }
21866
21867        let selection = self.selections.newest::<OffsetUtf16>(cx);
21868        let range = selection.range();
21869
21870        Some(UTF16Selection {
21871            range: range.start.0..range.end.0,
21872            reversed: selection.reversed,
21873        })
21874    }
21875
21876    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21877        let snapshot = self.buffer.read(cx).read(cx);
21878        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21879        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21880    }
21881
21882    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21883        self.clear_highlights::<InputComposition>(cx);
21884        self.ime_transaction.take();
21885    }
21886
21887    fn replace_text_in_range(
21888        &mut self,
21889        range_utf16: Option<Range<usize>>,
21890        text: &str,
21891        window: &mut Window,
21892        cx: &mut Context<Self>,
21893    ) {
21894        if !self.input_enabled {
21895            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21896            return;
21897        }
21898
21899        self.transact(window, cx, |this, window, cx| {
21900            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21901                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21902                Some(this.selection_replacement_ranges(range_utf16, cx))
21903            } else {
21904                this.marked_text_ranges(cx)
21905            };
21906
21907            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21908                let newest_selection_id = this.selections.newest_anchor().id;
21909                this.selections
21910                    .all::<OffsetUtf16>(cx)
21911                    .iter()
21912                    .zip(ranges_to_replace.iter())
21913                    .find_map(|(selection, range)| {
21914                        if selection.id == newest_selection_id {
21915                            Some(
21916                                (range.start.0 as isize - selection.head().0 as isize)
21917                                    ..(range.end.0 as isize - selection.head().0 as isize),
21918                            )
21919                        } else {
21920                            None
21921                        }
21922                    })
21923            });
21924
21925            cx.emit(EditorEvent::InputHandled {
21926                utf16_range_to_replace: range_to_replace,
21927                text: text.into(),
21928            });
21929
21930            if let Some(new_selected_ranges) = new_selected_ranges {
21931                this.change_selections(None, window, cx, |selections| {
21932                    selections.select_ranges(new_selected_ranges)
21933                });
21934                this.backspace(&Default::default(), window, cx);
21935            }
21936
21937            this.handle_input(text, window, cx);
21938        });
21939
21940        if let Some(transaction) = self.ime_transaction {
21941            self.buffer.update(cx, |buffer, cx| {
21942                buffer.group_until_transaction(transaction, cx);
21943            });
21944        }
21945
21946        self.unmark_text(window, cx);
21947    }
21948
21949    fn replace_and_mark_text_in_range(
21950        &mut self,
21951        range_utf16: Option<Range<usize>>,
21952        text: &str,
21953        new_selected_range_utf16: Option<Range<usize>>,
21954        window: &mut Window,
21955        cx: &mut Context<Self>,
21956    ) {
21957        if !self.input_enabled {
21958            return;
21959        }
21960
21961        let transaction = self.transact(window, cx, |this, window, cx| {
21962            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21963                let snapshot = this.buffer.read(cx).read(cx);
21964                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21965                    for marked_range in &mut marked_ranges {
21966                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21967                        marked_range.start.0 += relative_range_utf16.start;
21968                        marked_range.start =
21969                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21970                        marked_range.end =
21971                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21972                    }
21973                }
21974                Some(marked_ranges)
21975            } else if let Some(range_utf16) = range_utf16 {
21976                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21977                Some(this.selection_replacement_ranges(range_utf16, cx))
21978            } else {
21979                None
21980            };
21981
21982            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21983                let newest_selection_id = this.selections.newest_anchor().id;
21984                this.selections
21985                    .all::<OffsetUtf16>(cx)
21986                    .iter()
21987                    .zip(ranges_to_replace.iter())
21988                    .find_map(|(selection, range)| {
21989                        if selection.id == newest_selection_id {
21990                            Some(
21991                                (range.start.0 as isize - selection.head().0 as isize)
21992                                    ..(range.end.0 as isize - selection.head().0 as isize),
21993                            )
21994                        } else {
21995                            None
21996                        }
21997                    })
21998            });
21999
22000            cx.emit(EditorEvent::InputHandled {
22001                utf16_range_to_replace: range_to_replace,
22002                text: text.into(),
22003            });
22004
22005            if let Some(ranges) = ranges_to_replace {
22006                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22007            }
22008
22009            let marked_ranges = {
22010                let snapshot = this.buffer.read(cx).read(cx);
22011                this.selections
22012                    .disjoint_anchors()
22013                    .iter()
22014                    .map(|selection| {
22015                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22016                    })
22017                    .collect::<Vec<_>>()
22018            };
22019
22020            if text.is_empty() {
22021                this.unmark_text(window, cx);
22022            } else {
22023                this.highlight_text::<InputComposition>(
22024                    marked_ranges.clone(),
22025                    HighlightStyle {
22026                        underline: Some(UnderlineStyle {
22027                            thickness: px(1.),
22028                            color: None,
22029                            wavy: false,
22030                        }),
22031                        ..Default::default()
22032                    },
22033                    cx,
22034                );
22035            }
22036
22037            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22038            let use_autoclose = this.use_autoclose;
22039            let use_auto_surround = this.use_auto_surround;
22040            this.set_use_autoclose(false);
22041            this.set_use_auto_surround(false);
22042            this.handle_input(text, window, cx);
22043            this.set_use_autoclose(use_autoclose);
22044            this.set_use_auto_surround(use_auto_surround);
22045
22046            if let Some(new_selected_range) = new_selected_range_utf16 {
22047                let snapshot = this.buffer.read(cx).read(cx);
22048                let new_selected_ranges = marked_ranges
22049                    .into_iter()
22050                    .map(|marked_range| {
22051                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22052                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22053                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22054                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22055                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22056                    })
22057                    .collect::<Vec<_>>();
22058
22059                drop(snapshot);
22060                this.change_selections(None, window, cx, |selections| {
22061                    selections.select_ranges(new_selected_ranges)
22062                });
22063            }
22064        });
22065
22066        self.ime_transaction = self.ime_transaction.or(transaction);
22067        if let Some(transaction) = self.ime_transaction {
22068            self.buffer.update(cx, |buffer, cx| {
22069                buffer.group_until_transaction(transaction, cx);
22070            });
22071        }
22072
22073        if self.text_highlights::<InputComposition>(cx).is_none() {
22074            self.ime_transaction.take();
22075        }
22076    }
22077
22078    fn bounds_for_range(
22079        &mut self,
22080        range_utf16: Range<usize>,
22081        element_bounds: gpui::Bounds<Pixels>,
22082        window: &mut Window,
22083        cx: &mut Context<Self>,
22084    ) -> Option<gpui::Bounds<Pixels>> {
22085        let text_layout_details = self.text_layout_details(window);
22086        let gpui::Size {
22087            width: em_width,
22088            height: line_height,
22089        } = self.character_size(window);
22090
22091        let snapshot = self.snapshot(window, cx);
22092        let scroll_position = snapshot.scroll_position();
22093        let scroll_left = scroll_position.x * em_width;
22094
22095        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22096        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22097            + self.gutter_dimensions.width
22098            + self.gutter_dimensions.margin;
22099        let y = line_height * (start.row().as_f32() - scroll_position.y);
22100
22101        Some(Bounds {
22102            origin: element_bounds.origin + point(x, y),
22103            size: size(em_width, line_height),
22104        })
22105    }
22106
22107    fn character_index_for_point(
22108        &mut self,
22109        point: gpui::Point<Pixels>,
22110        _window: &mut Window,
22111        _cx: &mut Context<Self>,
22112    ) -> Option<usize> {
22113        let position_map = self.last_position_map.as_ref()?;
22114        if !position_map.text_hitbox.contains(&point) {
22115            return None;
22116        }
22117        let display_point = position_map.point_for_position(point).previous_valid;
22118        let anchor = position_map
22119            .snapshot
22120            .display_point_to_anchor(display_point, Bias::Left);
22121        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22122        Some(utf16_offset.0)
22123    }
22124}
22125
22126trait SelectionExt {
22127    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22128    fn spanned_rows(
22129        &self,
22130        include_end_if_at_line_start: bool,
22131        map: &DisplaySnapshot,
22132    ) -> Range<MultiBufferRow>;
22133}
22134
22135impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22136    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22137        let start = self
22138            .start
22139            .to_point(&map.buffer_snapshot)
22140            .to_display_point(map);
22141        let end = self
22142            .end
22143            .to_point(&map.buffer_snapshot)
22144            .to_display_point(map);
22145        if self.reversed {
22146            end..start
22147        } else {
22148            start..end
22149        }
22150    }
22151
22152    fn spanned_rows(
22153        &self,
22154        include_end_if_at_line_start: bool,
22155        map: &DisplaySnapshot,
22156    ) -> Range<MultiBufferRow> {
22157        let start = self.start.to_point(&map.buffer_snapshot);
22158        let mut end = self.end.to_point(&map.buffer_snapshot);
22159        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22160            end.row -= 1;
22161        }
22162
22163        let buffer_start = map.prev_line_boundary(start).0;
22164        let buffer_end = map.next_line_boundary(end).0;
22165        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22166    }
22167}
22168
22169impl<T: InvalidationRegion> InvalidationStack<T> {
22170    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22171    where
22172        S: Clone + ToOffset,
22173    {
22174        while let Some(region) = self.last() {
22175            let all_selections_inside_invalidation_ranges =
22176                if selections.len() == region.ranges().len() {
22177                    selections
22178                        .iter()
22179                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22180                        .all(|(selection, invalidation_range)| {
22181                            let head = selection.head().to_offset(buffer);
22182                            invalidation_range.start <= head && invalidation_range.end >= head
22183                        })
22184                } else {
22185                    false
22186                };
22187
22188            if all_selections_inside_invalidation_ranges {
22189                break;
22190            } else {
22191                self.pop();
22192            }
22193        }
22194    }
22195}
22196
22197impl<T> Default for InvalidationStack<T> {
22198    fn default() -> Self {
22199        Self(Default::default())
22200    }
22201}
22202
22203impl<T> Deref for InvalidationStack<T> {
22204    type Target = Vec<T>;
22205
22206    fn deref(&self) -> &Self::Target {
22207        &self.0
22208    }
22209}
22210
22211impl<T> DerefMut for InvalidationStack<T> {
22212    fn deref_mut(&mut self) -> &mut Self::Target {
22213        &mut self.0
22214    }
22215}
22216
22217impl InvalidationRegion for SnippetState {
22218    fn ranges(&self) -> &[Range<Anchor>] {
22219        &self.ranges[self.active_index]
22220    }
22221}
22222
22223fn inline_completion_edit_text(
22224    current_snapshot: &BufferSnapshot,
22225    edits: &[(Range<Anchor>, String)],
22226    edit_preview: &EditPreview,
22227    include_deletions: bool,
22228    cx: &App,
22229) -> HighlightedText {
22230    let edits = edits
22231        .iter()
22232        .map(|(anchor, text)| {
22233            (
22234                anchor.start.text_anchor..anchor.end.text_anchor,
22235                text.clone(),
22236            )
22237        })
22238        .collect::<Vec<_>>();
22239
22240    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22241}
22242
22243pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22244    match severity {
22245        lsp::DiagnosticSeverity::ERROR => colors.error,
22246        lsp::DiagnosticSeverity::WARNING => colors.warning,
22247        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22248        lsp::DiagnosticSeverity::HINT => colors.info,
22249        _ => colors.ignored,
22250    }
22251}
22252
22253pub fn styled_runs_for_code_label<'a>(
22254    label: &'a CodeLabel,
22255    syntax_theme: &'a theme::SyntaxTheme,
22256) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22257    let fade_out = HighlightStyle {
22258        fade_out: Some(0.35),
22259        ..Default::default()
22260    };
22261
22262    let mut prev_end = label.filter_range.end;
22263    label
22264        .runs
22265        .iter()
22266        .enumerate()
22267        .flat_map(move |(ix, (range, highlight_id))| {
22268            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22269                style
22270            } else {
22271                return Default::default();
22272            };
22273            let mut muted_style = style;
22274            muted_style.highlight(fade_out);
22275
22276            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22277            if range.start >= label.filter_range.end {
22278                if range.start > prev_end {
22279                    runs.push((prev_end..range.start, fade_out));
22280                }
22281                runs.push((range.clone(), muted_style));
22282            } else if range.end <= label.filter_range.end {
22283                runs.push((range.clone(), style));
22284            } else {
22285                runs.push((range.start..label.filter_range.end, style));
22286                runs.push((label.filter_range.end..range.end, muted_style));
22287            }
22288            prev_end = cmp::max(prev_end, range.end);
22289
22290            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22291                runs.push((prev_end..label.text.len(), fade_out));
22292            }
22293
22294            runs
22295        })
22296}
22297
22298pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22299    let mut prev_index = 0;
22300    let mut prev_codepoint: Option<char> = None;
22301    text.char_indices()
22302        .chain([(text.len(), '\0')])
22303        .filter_map(move |(index, codepoint)| {
22304            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22305            let is_boundary = index == text.len()
22306                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22307                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22308            if is_boundary {
22309                let chunk = &text[prev_index..index];
22310                prev_index = index;
22311                Some(chunk)
22312            } else {
22313                None
22314            }
22315        })
22316}
22317
22318pub trait RangeToAnchorExt: Sized {
22319    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22320
22321    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22322        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22323        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22324    }
22325}
22326
22327impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22328    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22329        let start_offset = self.start.to_offset(snapshot);
22330        let end_offset = self.end.to_offset(snapshot);
22331        if start_offset == end_offset {
22332            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22333        } else {
22334            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22335        }
22336    }
22337}
22338
22339pub trait RowExt {
22340    fn as_f32(&self) -> f32;
22341
22342    fn next_row(&self) -> Self;
22343
22344    fn previous_row(&self) -> Self;
22345
22346    fn minus(&self, other: Self) -> u32;
22347}
22348
22349impl RowExt for DisplayRow {
22350    fn as_f32(&self) -> f32 {
22351        self.0 as f32
22352    }
22353
22354    fn next_row(&self) -> Self {
22355        Self(self.0 + 1)
22356    }
22357
22358    fn previous_row(&self) -> Self {
22359        Self(self.0.saturating_sub(1))
22360    }
22361
22362    fn minus(&self, other: Self) -> u32 {
22363        self.0 - other.0
22364    }
22365}
22366
22367impl RowExt for MultiBufferRow {
22368    fn as_f32(&self) -> f32 {
22369        self.0 as f32
22370    }
22371
22372    fn next_row(&self) -> Self {
22373        Self(self.0 + 1)
22374    }
22375
22376    fn previous_row(&self) -> Self {
22377        Self(self.0.saturating_sub(1))
22378    }
22379
22380    fn minus(&self, other: Self) -> u32 {
22381        self.0 - other.0
22382    }
22383}
22384
22385trait RowRangeExt {
22386    type Row;
22387
22388    fn len(&self) -> usize;
22389
22390    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22391}
22392
22393impl RowRangeExt for Range<MultiBufferRow> {
22394    type Row = MultiBufferRow;
22395
22396    fn len(&self) -> usize {
22397        (self.end.0 - self.start.0) as usize
22398    }
22399
22400    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22401        (self.start.0..self.end.0).map(MultiBufferRow)
22402    }
22403}
22404
22405impl RowRangeExt for Range<DisplayRow> {
22406    type Row = DisplayRow;
22407
22408    fn len(&self) -> usize {
22409        (self.end.0 - self.start.0) as usize
22410    }
22411
22412    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22413        (self.start.0..self.end.0).map(DisplayRow)
22414    }
22415}
22416
22417/// If select range has more than one line, we
22418/// just point the cursor to range.start.
22419fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22420    if range.start.row == range.end.row {
22421        range
22422    } else {
22423        range.start..range.start
22424    }
22425}
22426pub struct KillRing(ClipboardItem);
22427impl Global for KillRing {}
22428
22429const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22430
22431enum BreakpointPromptEditAction {
22432    Log,
22433    Condition,
22434    HitCondition,
22435}
22436
22437struct BreakpointPromptEditor {
22438    pub(crate) prompt: Entity<Editor>,
22439    editor: WeakEntity<Editor>,
22440    breakpoint_anchor: Anchor,
22441    breakpoint: Breakpoint,
22442    edit_action: BreakpointPromptEditAction,
22443    block_ids: HashSet<CustomBlockId>,
22444    editor_margins: Arc<Mutex<EditorMargins>>,
22445    _subscriptions: Vec<Subscription>,
22446}
22447
22448impl BreakpointPromptEditor {
22449    const MAX_LINES: u8 = 4;
22450
22451    fn new(
22452        editor: WeakEntity<Editor>,
22453        breakpoint_anchor: Anchor,
22454        breakpoint: Breakpoint,
22455        edit_action: BreakpointPromptEditAction,
22456        window: &mut Window,
22457        cx: &mut Context<Self>,
22458    ) -> Self {
22459        let base_text = match edit_action {
22460            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22461            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22462            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22463        }
22464        .map(|msg| msg.to_string())
22465        .unwrap_or_default();
22466
22467        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22468        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22469
22470        let prompt = cx.new(|cx| {
22471            let mut prompt = Editor::new(
22472                EditorMode::AutoHeight {
22473                    max_lines: Self::MAX_LINES as usize,
22474                },
22475                buffer,
22476                None,
22477                window,
22478                cx,
22479            );
22480            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22481            prompt.set_show_cursor_when_unfocused(false, cx);
22482            prompt.set_placeholder_text(
22483                match edit_action {
22484                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22485                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22486                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22487                },
22488                cx,
22489            );
22490
22491            prompt
22492        });
22493
22494        Self {
22495            prompt,
22496            editor,
22497            breakpoint_anchor,
22498            breakpoint,
22499            edit_action,
22500            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22501            block_ids: Default::default(),
22502            _subscriptions: vec![],
22503        }
22504    }
22505
22506    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22507        self.block_ids.extend(block_ids)
22508    }
22509
22510    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22511        if let Some(editor) = self.editor.upgrade() {
22512            let message = self
22513                .prompt
22514                .read(cx)
22515                .buffer
22516                .read(cx)
22517                .as_singleton()
22518                .expect("A multi buffer in breakpoint prompt isn't possible")
22519                .read(cx)
22520                .as_rope()
22521                .to_string();
22522
22523            editor.update(cx, |editor, cx| {
22524                editor.edit_breakpoint_at_anchor(
22525                    self.breakpoint_anchor,
22526                    self.breakpoint.clone(),
22527                    match self.edit_action {
22528                        BreakpointPromptEditAction::Log => {
22529                            BreakpointEditAction::EditLogMessage(message.into())
22530                        }
22531                        BreakpointPromptEditAction::Condition => {
22532                            BreakpointEditAction::EditCondition(message.into())
22533                        }
22534                        BreakpointPromptEditAction::HitCondition => {
22535                            BreakpointEditAction::EditHitCondition(message.into())
22536                        }
22537                    },
22538                    cx,
22539                );
22540
22541                editor.remove_blocks(self.block_ids.clone(), None, cx);
22542                cx.focus_self(window);
22543            });
22544        }
22545    }
22546
22547    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22548        self.editor
22549            .update(cx, |editor, cx| {
22550                editor.remove_blocks(self.block_ids.clone(), None, cx);
22551                window.focus(&editor.focus_handle);
22552            })
22553            .log_err();
22554    }
22555
22556    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22557        let settings = ThemeSettings::get_global(cx);
22558        let text_style = TextStyle {
22559            color: if self.prompt.read(cx).read_only(cx) {
22560                cx.theme().colors().text_disabled
22561            } else {
22562                cx.theme().colors().text
22563            },
22564            font_family: settings.buffer_font.family.clone(),
22565            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22566            font_size: settings.buffer_font_size(cx).into(),
22567            font_weight: settings.buffer_font.weight,
22568            line_height: relative(settings.buffer_line_height.value()),
22569            ..Default::default()
22570        };
22571        EditorElement::new(
22572            &self.prompt,
22573            EditorStyle {
22574                background: cx.theme().colors().editor_background,
22575                local_player: cx.theme().players().local(),
22576                text: text_style,
22577                ..Default::default()
22578            },
22579        )
22580    }
22581}
22582
22583impl Render for BreakpointPromptEditor {
22584    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22585        let editor_margins = *self.editor_margins.lock();
22586        let gutter_dimensions = editor_margins.gutter;
22587        h_flex()
22588            .key_context("Editor")
22589            .bg(cx.theme().colors().editor_background)
22590            .border_y_1()
22591            .border_color(cx.theme().status().info_border)
22592            .size_full()
22593            .py(window.line_height() / 2.5)
22594            .on_action(cx.listener(Self::confirm))
22595            .on_action(cx.listener(Self::cancel))
22596            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22597            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22598    }
22599}
22600
22601impl Focusable for BreakpointPromptEditor {
22602    fn focus_handle(&self, cx: &App) -> FocusHandle {
22603        self.prompt.focus_handle(cx)
22604    }
22605}
22606
22607fn all_edits_insertions_or_deletions(
22608    edits: &Vec<(Range<Anchor>, String)>,
22609    snapshot: &MultiBufferSnapshot,
22610) -> bool {
22611    let mut all_insertions = true;
22612    let mut all_deletions = true;
22613
22614    for (range, new_text) in edits.iter() {
22615        let range_is_empty = range.to_offset(&snapshot).is_empty();
22616        let text_is_empty = new_text.is_empty();
22617
22618        if range_is_empty != text_is_empty {
22619            if range_is_empty {
22620                all_deletions = false;
22621            } else {
22622                all_insertions = false;
22623            }
22624        } else {
22625            return false;
22626        }
22627
22628        if !all_insertions && !all_deletions {
22629            return false;
22630        }
22631    }
22632    all_insertions || all_deletions
22633}
22634
22635struct MissingEditPredictionKeybindingTooltip;
22636
22637impl Render for MissingEditPredictionKeybindingTooltip {
22638    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22639        ui::tooltip_container(window, cx, |container, _, cx| {
22640            container
22641                .flex_shrink_0()
22642                .max_w_80()
22643                .min_h(rems_from_px(124.))
22644                .justify_between()
22645                .child(
22646                    v_flex()
22647                        .flex_1()
22648                        .text_ui_sm(cx)
22649                        .child(Label::new("Conflict with Accept Keybinding"))
22650                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22651                )
22652                .child(
22653                    h_flex()
22654                        .pb_1()
22655                        .gap_1()
22656                        .items_end()
22657                        .w_full()
22658                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22659                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22660                        }))
22661                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22662                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22663                        })),
22664                )
22665        })
22666    }
22667}
22668
22669#[derive(Debug, Clone, Copy, PartialEq)]
22670pub struct LineHighlight {
22671    pub background: Background,
22672    pub border: Option<gpui::Hsla>,
22673    pub include_gutter: bool,
22674    pub type_id: Option<TypeId>,
22675}
22676
22677fn render_diff_hunk_controls(
22678    row: u32,
22679    status: &DiffHunkStatus,
22680    hunk_range: Range<Anchor>,
22681    is_created_file: bool,
22682    line_height: Pixels,
22683    editor: &Entity<Editor>,
22684    _window: &mut Window,
22685    cx: &mut App,
22686) -> AnyElement {
22687    h_flex()
22688        .h(line_height)
22689        .mr_1()
22690        .gap_1()
22691        .px_0p5()
22692        .pb_1()
22693        .border_x_1()
22694        .border_b_1()
22695        .border_color(cx.theme().colors().border_variant)
22696        .rounded_b_lg()
22697        .bg(cx.theme().colors().editor_background)
22698        .gap_1()
22699        .block_mouse_except_scroll()
22700        .shadow_md()
22701        .child(if status.has_secondary_hunk() {
22702            Button::new(("stage", row as u64), "Stage")
22703                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22704                .tooltip({
22705                    let focus_handle = editor.focus_handle(cx);
22706                    move |window, cx| {
22707                        Tooltip::for_action_in(
22708                            "Stage Hunk",
22709                            &::git::ToggleStaged,
22710                            &focus_handle,
22711                            window,
22712                            cx,
22713                        )
22714                    }
22715                })
22716                .on_click({
22717                    let editor = editor.clone();
22718                    move |_event, _window, cx| {
22719                        editor.update(cx, |editor, cx| {
22720                            editor.stage_or_unstage_diff_hunks(
22721                                true,
22722                                vec![hunk_range.start..hunk_range.start],
22723                                cx,
22724                            );
22725                        });
22726                    }
22727                })
22728        } else {
22729            Button::new(("unstage", row as u64), "Unstage")
22730                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22731                .tooltip({
22732                    let focus_handle = editor.focus_handle(cx);
22733                    move |window, cx| {
22734                        Tooltip::for_action_in(
22735                            "Unstage Hunk",
22736                            &::git::ToggleStaged,
22737                            &focus_handle,
22738                            window,
22739                            cx,
22740                        )
22741                    }
22742                })
22743                .on_click({
22744                    let editor = editor.clone();
22745                    move |_event, _window, cx| {
22746                        editor.update(cx, |editor, cx| {
22747                            editor.stage_or_unstage_diff_hunks(
22748                                false,
22749                                vec![hunk_range.start..hunk_range.start],
22750                                cx,
22751                            );
22752                        });
22753                    }
22754                })
22755        })
22756        .child(
22757            Button::new(("restore", row as u64), "Restore")
22758                .tooltip({
22759                    let focus_handle = editor.focus_handle(cx);
22760                    move |window, cx| {
22761                        Tooltip::for_action_in(
22762                            "Restore Hunk",
22763                            &::git::Restore,
22764                            &focus_handle,
22765                            window,
22766                            cx,
22767                        )
22768                    }
22769                })
22770                .on_click({
22771                    let editor = editor.clone();
22772                    move |_event, window, cx| {
22773                        editor.update(cx, |editor, cx| {
22774                            let snapshot = editor.snapshot(window, cx);
22775                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22776                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22777                        });
22778                    }
22779                })
22780                .disabled(is_created_file),
22781        )
22782        .when(
22783            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22784            |el| {
22785                el.child(
22786                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22787                        .shape(IconButtonShape::Square)
22788                        .icon_size(IconSize::Small)
22789                        // .disabled(!has_multiple_hunks)
22790                        .tooltip({
22791                            let focus_handle = editor.focus_handle(cx);
22792                            move |window, cx| {
22793                                Tooltip::for_action_in(
22794                                    "Next Hunk",
22795                                    &GoToHunk,
22796                                    &focus_handle,
22797                                    window,
22798                                    cx,
22799                                )
22800                            }
22801                        })
22802                        .on_click({
22803                            let editor = editor.clone();
22804                            move |_event, window, cx| {
22805                                editor.update(cx, |editor, cx| {
22806                                    let snapshot = editor.snapshot(window, cx);
22807                                    let position =
22808                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22809                                    editor.go_to_hunk_before_or_after_position(
22810                                        &snapshot,
22811                                        position,
22812                                        Direction::Next,
22813                                        window,
22814                                        cx,
22815                                    );
22816                                    editor.expand_selected_diff_hunks(cx);
22817                                });
22818                            }
22819                        }),
22820                )
22821                .child(
22822                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22823                        .shape(IconButtonShape::Square)
22824                        .icon_size(IconSize::Small)
22825                        // .disabled(!has_multiple_hunks)
22826                        .tooltip({
22827                            let focus_handle = editor.focus_handle(cx);
22828                            move |window, cx| {
22829                                Tooltip::for_action_in(
22830                                    "Previous Hunk",
22831                                    &GoToPreviousHunk,
22832                                    &focus_handle,
22833                                    window,
22834                                    cx,
22835                                )
22836                            }
22837                        })
22838                        .on_click({
22839                            let editor = editor.clone();
22840                            move |_event, window, cx| {
22841                                editor.update(cx, |editor, cx| {
22842                                    let snapshot = editor.snapshot(window, cx);
22843                                    let point =
22844                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22845                                    editor.go_to_hunk_before_or_after_position(
22846                                        &snapshot,
22847                                        point,
22848                                        Direction::Prev,
22849                                        window,
22850                                        cx,
22851                                    );
22852                                    editor.expand_selected_diff_hunks(cx);
22853                                });
22854                            }
22855                        }),
22856                )
22857            },
22858        )
22859        .into_any_element()
22860}