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;
   18mod 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 display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64pub use editor_settings::{
   65    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   66    ShowScrollbar,
   67};
   68use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   69pub use editor_settings_controls::*;
   70use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   71pub use element::{
   72    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   73};
   74use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   75use futures::{
   76    FutureExt,
   77    future::{self, Shared, join},
   78};
   79use fuzzy::StringMatchCandidate;
   80
   81use ::git::blame::BlameEntry;
   82use ::git::{Restore, blame::ParsedCommitMessage};
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use git::blame::{GitBlame, GlobalBlameRenderer};
   88use gpui::{
   89    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   90    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   91    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   92    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   93    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   94    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   95    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   96    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   97};
   98use highlight_matching_bracket::refresh_matching_bracket_highlights;
   99use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  100pub use hover_popover::hover_markdown_style;
  101use hover_popover::{HoverState, hide_hover};
  102use indent_guides::ActiveIndentGuidesState;
  103use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  104pub use inline_completion::Direction;
  105use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  106pub use items::MAX_TAB_TITLE_LEN;
  107use itertools::Itertools;
  108use language::{
  109    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  110    CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText,
  111    IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TextObject,
  112    TransactionId, TreeSitterOptions, WordsQuery,
  113    language_settings::{
  114        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  115        all_language_settings, language_settings,
  116    },
  117    point_from_lsp, text_diff_with_options,
  118};
  119use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  120use linked_editing_ranges::refresh_linked_ranges;
  121use markdown::Markdown;
  122use mouse_context_menu::MouseContextMenu;
  123use persistence::DB;
  124use project::{
  125    BreakpointWithPosition, ProjectPath,
  126    debugger::{
  127        breakpoint_store::{
  128            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  129            BreakpointStoreEvent,
  130        },
  131        session::{Session, SessionEvent},
  132    },
  133    project_settings::DiagnosticSeverity,
  134};
  135
  136pub use git::blame::BlameRenderer;
  137pub use proposed_changes_editor::{
  138    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  139};
  140use smallvec::smallvec;
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::SmallVec;
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::hover_links::{find_url, find_url_from_range};
  215use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  252    alt: true,
  253    shift: true,
  254    control: false,
  255    platform: false,
  256    function: false,
  257};
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  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, Arc<[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(bool),
  720}
  721
  722impl MinimapVisibility {
  723    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  724        if mode.is_full() {
  725            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  726        } else {
  727            Self::Disabled
  728        }
  729    }
  730
  731    fn disabled(&self) -> bool {
  732        match *self {
  733            Self::Disabled => true,
  734            _ => false,
  735        }
  736    }
  737
  738    fn visible(&self) -> bool {
  739        match *self {
  740            Self::Enabled(visible) => visible,
  741            _ => false,
  742        }
  743    }
  744
  745    fn toggle_visibility(&self) -> Self {
  746        match *self {
  747            Self::Enabled(visible) => Self::Enabled(!visible),
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751}
  752
  753#[derive(Clone, Debug)]
  754struct RunnableTasks {
  755    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  756    offset: multi_buffer::Anchor,
  757    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  758    column: u32,
  759    // Values of all named captures, including those starting with '_'
  760    extra_variables: HashMap<String, String>,
  761    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  762    context_range: Range<BufferOffset>,
  763}
  764
  765impl RunnableTasks {
  766    fn resolve<'a>(
  767        &'a self,
  768        cx: &'a task::TaskContext,
  769    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  770        self.templates.iter().filter_map(|(kind, template)| {
  771            template
  772                .resolve_task(&kind.to_id_base(), cx)
  773                .map(|task| (kind.clone(), task))
  774        })
  775    }
  776}
  777
  778#[derive(Clone)]
  779struct ResolvedTasks {
  780    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  781    position: Anchor,
  782}
  783
  784#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  785struct BufferOffset(usize);
  786
  787// Addons allow storing per-editor state in other crates (e.g. Vim)
  788pub trait Addon: 'static {
  789    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  790
  791    fn render_buffer_header_controls(
  792        &self,
  793        _: &ExcerptInfo,
  794        _: &Window,
  795        _: &App,
  796    ) -> Option<AnyElement> {
  797        None
  798    }
  799
  800    fn to_any(&self) -> &dyn std::any::Any;
  801
  802    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  803        None
  804    }
  805}
  806
  807/// A set of caret positions, registered when the editor was edited.
  808pub struct ChangeList {
  809    changes: Vec<Vec<Anchor>>,
  810    /// Currently "selected" change.
  811    position: Option<usize>,
  812}
  813
  814impl ChangeList {
  815    pub fn new() -> Self {
  816        Self {
  817            changes: Vec::new(),
  818            position: None,
  819        }
  820    }
  821
  822    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  823    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  824    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  825        if self.changes.is_empty() {
  826            return None;
  827        }
  828
  829        let prev = self.position.unwrap_or(self.changes.len());
  830        let next = if direction == Direction::Prev {
  831            prev.saturating_sub(count)
  832        } else {
  833            (prev + count).min(self.changes.len() - 1)
  834        };
  835        self.position = Some(next);
  836        self.changes.get(next).map(|anchors| anchors.as_slice())
  837    }
  838
  839    /// Adds a new change to the list, resetting the change list position.
  840    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  841        self.position.take();
  842        if pop_state {
  843            self.changes.pop();
  844        }
  845        self.changes.push(new_positions.clone());
  846    }
  847
  848    pub fn last(&self) -> Option<&[Anchor]> {
  849        self.changes.last().map(|anchors| anchors.as_slice())
  850    }
  851}
  852
  853#[derive(Clone)]
  854struct InlineBlamePopoverState {
  855    scroll_handle: ScrollHandle,
  856    commit_message: Option<ParsedCommitMessage>,
  857    markdown: Entity<Markdown>,
  858}
  859
  860struct InlineBlamePopover {
  861    position: gpui::Point<Pixels>,
  862    show_task: Option<Task<()>>,
  863    hide_task: Option<Task<()>>,
  864    popover_bounds: Option<Bounds<Pixels>>,
  865    popover_state: InlineBlamePopoverState,
  866}
  867
  868/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  869/// a breakpoint on them.
  870#[derive(Clone, Copy, Debug)]
  871struct PhantomBreakpointIndicator {
  872    display_row: DisplayRow,
  873    /// There's a small debounce between hovering over the line and showing the indicator.
  874    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  875    is_active: bool,
  876    collides_with_existing_breakpoint: bool,
  877}
  878/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  879///
  880/// See the [module level documentation](self) for more information.
  881pub struct Editor {
  882    focus_handle: FocusHandle,
  883    last_focused_descendant: Option<WeakFocusHandle>,
  884    /// The text buffer being edited
  885    buffer: Entity<MultiBuffer>,
  886    /// Map of how text in the buffer should be displayed.
  887    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  888    pub display_map: Entity<DisplayMap>,
  889    pub selections: SelectionsCollection,
  890    pub scroll_manager: ScrollManager,
  891    /// When inline assist editors are linked, they all render cursors because
  892    /// typing enters text into each of them, even the ones that aren't focused.
  893    pub(crate) show_cursor_when_unfocused: bool,
  894    columnar_selection_tail: Option<Anchor>,
  895    add_selections_state: Option<AddSelectionsState>,
  896    select_next_state: Option<SelectNextState>,
  897    select_prev_state: Option<SelectNextState>,
  898    selection_history: SelectionHistory,
  899    autoclose_regions: Vec<AutocloseRegion>,
  900    snippet_stack: InvalidationStack<SnippetState>,
  901    select_syntax_node_history: SelectSyntaxNodeHistory,
  902    ime_transaction: Option<TransactionId>,
  903    pub diagnostics_max_severity: DiagnosticSeverity,
  904    active_diagnostics: ActiveDiagnostic,
  905    show_inline_diagnostics: bool,
  906    inline_diagnostics_update: Task<()>,
  907    inline_diagnostics_enabled: bool,
  908    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  909    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  910    hard_wrap: Option<usize>,
  911
  912    // TODO: make this a access method
  913    pub project: Option<Entity<Project>>,
  914    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  915    completion_provider: Option<Box<dyn CompletionProvider>>,
  916    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  917    blink_manager: Entity<BlinkManager>,
  918    show_cursor_names: bool,
  919    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  920    pub show_local_selections: bool,
  921    mode: EditorMode,
  922    show_breadcrumbs: bool,
  923    show_gutter: bool,
  924    show_scrollbars: bool,
  925    minimap_visibility: MinimapVisibility,
  926    disable_expand_excerpt_buttons: bool,
  927    show_line_numbers: Option<bool>,
  928    use_relative_line_numbers: Option<bool>,
  929    show_git_diff_gutter: Option<bool>,
  930    show_code_actions: Option<bool>,
  931    show_runnables: Option<bool>,
  932    show_breakpoints: Option<bool>,
  933    show_wrap_guides: Option<bool>,
  934    show_indent_guides: Option<bool>,
  935    placeholder_text: Option<Arc<str>>,
  936    highlight_order: usize,
  937    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  938    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  939    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  940    scrollbar_marker_state: ScrollbarMarkerState,
  941    active_indent_guides_state: ActiveIndentGuidesState,
  942    nav_history: Option<ItemNavHistory>,
  943    context_menu: RefCell<Option<CodeContextMenu>>,
  944    context_menu_options: Option<ContextMenuOptions>,
  945    mouse_context_menu: Option<MouseContextMenu>,
  946    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  947    inline_blame_popover: Option<InlineBlamePopover>,
  948    signature_help_state: SignatureHelpState,
  949    auto_signature_help: Option<bool>,
  950    find_all_references_task_sources: Vec<Anchor>,
  951    next_completion_id: CompletionId,
  952    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  953    code_actions_task: Option<Task<Result<()>>>,
  954    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  955    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    document_highlights_task: Option<Task<()>>,
  957    linked_editing_range_task: Option<Task<Option<()>>>,
  958    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  959    pending_rename: Option<RenameState>,
  960    searchable: bool,
  961    cursor_shape: CursorShape,
  962    current_line_highlight: Option<CurrentLineHighlight>,
  963    collapse_matches: bool,
  964    autoindent_mode: Option<AutoindentMode>,
  965    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  966    input_enabled: bool,
  967    use_modal_editing: bool,
  968    read_only: bool,
  969    leader_id: Option<CollaboratorId>,
  970    remote_id: Option<ViewId>,
  971    pub hover_state: HoverState,
  972    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  973    gutter_hovered: bool,
  974    hovered_link_state: Option<HoveredLinkState>,
  975    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  976    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  977    active_inline_completion: Option<InlineCompletionState>,
  978    /// Used to prevent flickering as the user types while the menu is open
  979    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  980    edit_prediction_settings: EditPredictionSettings,
  981    inline_completions_hidden_for_vim_mode: bool,
  982    show_inline_completions_override: Option<bool>,
  983    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  984    edit_prediction_preview: EditPredictionPreview,
  985    edit_prediction_indent_conflict: bool,
  986    edit_prediction_requires_modifier_in_indent_conflict: bool,
  987    inlay_hint_cache: InlayHintCache,
  988    next_inlay_id: usize,
  989    _subscriptions: Vec<Subscription>,
  990    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  991    gutter_dimensions: GutterDimensions,
  992    style: Option<EditorStyle>,
  993    text_style_refinement: Option<TextStyleRefinement>,
  994    next_editor_action_id: EditorActionId,
  995    editor_actions:
  996        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  997    use_autoclose: bool,
  998    use_auto_surround: bool,
  999    auto_replace_emoji_shortcode: bool,
 1000    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1001    show_git_blame_gutter: bool,
 1002    show_git_blame_inline: bool,
 1003    show_git_blame_inline_delay_task: Option<Task<()>>,
 1004    git_blame_inline_enabled: bool,
 1005    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1006    serialize_dirty_buffers: bool,
 1007    show_selection_menu: Option<bool>,
 1008    blame: Option<Entity<GitBlame>>,
 1009    blame_subscription: Option<Subscription>,
 1010    custom_context_menu: Option<
 1011        Box<
 1012            dyn 'static
 1013                + Fn(
 1014                    &mut Self,
 1015                    DisplayPoint,
 1016                    &mut Window,
 1017                    &mut Context<Self>,
 1018                ) -> Option<Entity<ui::ContextMenu>>,
 1019        >,
 1020    >,
 1021    last_bounds: Option<Bounds<Pixels>>,
 1022    last_position_map: Option<Rc<PositionMap>>,
 1023    expect_bounds_change: Option<Bounds<Pixels>>,
 1024    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1025    tasks_update_task: Option<Task<()>>,
 1026    breakpoint_store: Option<Entity<BreakpointStore>>,
 1027    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1028    in_project_search: bool,
 1029    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1030    breadcrumb_header: Option<String>,
 1031    focused_block: Option<FocusedBlock>,
 1032    next_scroll_position: NextScrollCursorCenterTopBottom,
 1033    addons: HashMap<TypeId, Box<dyn Addon>>,
 1034    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1035    load_diff_task: Option<Shared<Task<()>>>,
 1036    /// Whether we are temporarily displaying a diff other than git's
 1037    temporary_diff_override: bool,
 1038    selection_mark_mode: bool,
 1039    toggle_fold_multiple_buffers: Task<()>,
 1040    _scroll_cursor_center_top_bottom_task: Task<()>,
 1041    serialize_selections: Task<()>,
 1042    serialize_folds: Task<()>,
 1043    mouse_cursor_hidden: bool,
 1044    minimap: Option<Entity<Self>>,
 1045    hide_mouse_mode: HideMouseMode,
 1046    pub change_list: ChangeList,
 1047    inline_value_cache: InlineValueCache,
 1048}
 1049
 1050#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1051enum NextScrollCursorCenterTopBottom {
 1052    #[default]
 1053    Center,
 1054    Top,
 1055    Bottom,
 1056}
 1057
 1058impl NextScrollCursorCenterTopBottom {
 1059    fn next(&self) -> Self {
 1060        match self {
 1061            Self::Center => Self::Top,
 1062            Self::Top => Self::Bottom,
 1063            Self::Bottom => Self::Center,
 1064        }
 1065    }
 1066}
 1067
 1068#[derive(Clone)]
 1069pub struct EditorSnapshot {
 1070    pub mode: EditorMode,
 1071    show_gutter: bool,
 1072    show_line_numbers: Option<bool>,
 1073    show_git_diff_gutter: Option<bool>,
 1074    show_runnables: Option<bool>,
 1075    show_breakpoints: Option<bool>,
 1076    git_blame_gutter_max_author_length: Option<usize>,
 1077    pub display_snapshot: DisplaySnapshot,
 1078    pub placeholder_text: Option<Arc<str>>,
 1079    is_focused: bool,
 1080    scroll_anchor: ScrollAnchor,
 1081    ongoing_scroll: OngoingScroll,
 1082    current_line_highlight: CurrentLineHighlight,
 1083    gutter_hovered: bool,
 1084}
 1085
 1086#[derive(Default, Debug, Clone, Copy)]
 1087pub struct GutterDimensions {
 1088    pub left_padding: Pixels,
 1089    pub right_padding: Pixels,
 1090    pub width: Pixels,
 1091    pub margin: Pixels,
 1092    pub git_blame_entries_width: Option<Pixels>,
 1093}
 1094
 1095impl GutterDimensions {
 1096    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1097        Self {
 1098            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1099            ..Default::default()
 1100        }
 1101    }
 1102
 1103    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1104        -cx.text_system().descent(font_id, font_size)
 1105    }
 1106    /// The full width of the space taken up by the gutter.
 1107    pub fn full_width(&self) -> Pixels {
 1108        self.margin + self.width
 1109    }
 1110
 1111    /// The width of the space reserved for the fold indicators,
 1112    /// use alongside 'justify_end' and `gutter_width` to
 1113    /// right align content with the line numbers
 1114    pub fn fold_area_width(&self) -> Pixels {
 1115        self.margin + self.right_padding
 1116    }
 1117}
 1118
 1119#[derive(Debug)]
 1120pub struct RemoteSelection {
 1121    pub replica_id: ReplicaId,
 1122    pub selection: Selection<Anchor>,
 1123    pub cursor_shape: CursorShape,
 1124    pub collaborator_id: CollaboratorId,
 1125    pub line_mode: bool,
 1126    pub user_name: Option<SharedString>,
 1127    pub color: PlayerColor,
 1128}
 1129
 1130#[derive(Clone, Debug)]
 1131struct SelectionHistoryEntry {
 1132    selections: Arc<[Selection<Anchor>]>,
 1133    select_next_state: Option<SelectNextState>,
 1134    select_prev_state: Option<SelectNextState>,
 1135    add_selections_state: Option<AddSelectionsState>,
 1136}
 1137
 1138enum SelectionHistoryMode {
 1139    Normal,
 1140    Undoing,
 1141    Redoing,
 1142}
 1143
 1144#[derive(Clone, PartialEq, Eq, Hash)]
 1145struct HoveredCursor {
 1146    replica_id: u16,
 1147    selection_id: usize,
 1148}
 1149
 1150impl Default for SelectionHistoryMode {
 1151    fn default() -> Self {
 1152        Self::Normal
 1153    }
 1154}
 1155
 1156#[derive(Default)]
 1157struct SelectionHistory {
 1158    #[allow(clippy::type_complexity)]
 1159    selections_by_transaction:
 1160        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1161    mode: SelectionHistoryMode,
 1162    undo_stack: VecDeque<SelectionHistoryEntry>,
 1163    redo_stack: VecDeque<SelectionHistoryEntry>,
 1164}
 1165
 1166impl SelectionHistory {
 1167    fn insert_transaction(
 1168        &mut self,
 1169        transaction_id: TransactionId,
 1170        selections: Arc<[Selection<Anchor>]>,
 1171    ) {
 1172        self.selections_by_transaction
 1173            .insert(transaction_id, (selections, None));
 1174    }
 1175
 1176    #[allow(clippy::type_complexity)]
 1177    fn transaction(
 1178        &self,
 1179        transaction_id: TransactionId,
 1180    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1181        self.selections_by_transaction.get(&transaction_id)
 1182    }
 1183
 1184    #[allow(clippy::type_complexity)]
 1185    fn transaction_mut(
 1186        &mut self,
 1187        transaction_id: TransactionId,
 1188    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1189        self.selections_by_transaction.get_mut(&transaction_id)
 1190    }
 1191
 1192    fn push(&mut self, entry: SelectionHistoryEntry) {
 1193        if !entry.selections.is_empty() {
 1194            match self.mode {
 1195                SelectionHistoryMode::Normal => {
 1196                    self.push_undo(entry);
 1197                    self.redo_stack.clear();
 1198                }
 1199                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1200                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1201            }
 1202        }
 1203    }
 1204
 1205    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1206        if self
 1207            .undo_stack
 1208            .back()
 1209            .map_or(true, |e| e.selections != entry.selections)
 1210        {
 1211            self.undo_stack.push_back(entry);
 1212            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1213                self.undo_stack.pop_front();
 1214            }
 1215        }
 1216    }
 1217
 1218    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1219        if self
 1220            .redo_stack
 1221            .back()
 1222            .map_or(true, |e| e.selections != entry.selections)
 1223        {
 1224            self.redo_stack.push_back(entry);
 1225            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1226                self.redo_stack.pop_front();
 1227            }
 1228        }
 1229    }
 1230}
 1231
 1232#[derive(Clone, Copy)]
 1233pub struct RowHighlightOptions {
 1234    pub autoscroll: bool,
 1235    pub include_gutter: bool,
 1236}
 1237
 1238impl Default for RowHighlightOptions {
 1239    fn default() -> Self {
 1240        Self {
 1241            autoscroll: Default::default(),
 1242            include_gutter: true,
 1243        }
 1244    }
 1245}
 1246
 1247struct RowHighlight {
 1248    index: usize,
 1249    range: Range<Anchor>,
 1250    color: Hsla,
 1251    options: RowHighlightOptions,
 1252    type_id: TypeId,
 1253}
 1254
 1255#[derive(Clone, Debug)]
 1256struct AddSelectionsState {
 1257    above: bool,
 1258    stack: Vec<usize>,
 1259}
 1260
 1261#[derive(Clone)]
 1262struct SelectNextState {
 1263    query: AhoCorasick,
 1264    wordwise: bool,
 1265    done: bool,
 1266}
 1267
 1268impl std::fmt::Debug for SelectNextState {
 1269    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1270        f.debug_struct(std::any::type_name::<Self>())
 1271            .field("wordwise", &self.wordwise)
 1272            .field("done", &self.done)
 1273            .finish()
 1274    }
 1275}
 1276
 1277#[derive(Debug)]
 1278struct AutocloseRegion {
 1279    selection_id: usize,
 1280    range: Range<Anchor>,
 1281    pair: BracketPair,
 1282}
 1283
 1284#[derive(Debug)]
 1285struct SnippetState {
 1286    ranges: Vec<Vec<Range<Anchor>>>,
 1287    active_index: usize,
 1288    choices: Vec<Option<Vec<String>>>,
 1289}
 1290
 1291#[doc(hidden)]
 1292pub struct RenameState {
 1293    pub range: Range<Anchor>,
 1294    pub old_name: Arc<str>,
 1295    pub editor: Entity<Editor>,
 1296    block_id: CustomBlockId,
 1297}
 1298
 1299struct InvalidationStack<T>(Vec<T>);
 1300
 1301struct RegisteredInlineCompletionProvider {
 1302    provider: Arc<dyn InlineCompletionProviderHandle>,
 1303    _subscription: Subscription,
 1304}
 1305
 1306#[derive(Debug, PartialEq, Eq)]
 1307pub struct ActiveDiagnosticGroup {
 1308    pub active_range: Range<Anchor>,
 1309    pub active_message: String,
 1310    pub group_id: usize,
 1311    pub blocks: HashSet<CustomBlockId>,
 1312}
 1313
 1314#[derive(Debug, PartialEq, Eq)]
 1315#[allow(clippy::large_enum_variant)]
 1316pub(crate) enum ActiveDiagnostic {
 1317    None,
 1318    All,
 1319    Group(ActiveDiagnosticGroup),
 1320}
 1321
 1322#[derive(Serialize, Deserialize, Clone, Debug)]
 1323pub struct ClipboardSelection {
 1324    /// The number of bytes in this selection.
 1325    pub len: usize,
 1326    /// Whether this was a full-line selection.
 1327    pub is_entire_line: bool,
 1328    /// The indentation of the first line when this content was originally copied.
 1329    pub first_line_indent: u32,
 1330}
 1331
 1332// selections, scroll behavior, was newest selection reversed
 1333type SelectSyntaxNodeHistoryState = (
 1334    Box<[Selection<usize>]>,
 1335    SelectSyntaxNodeScrollBehavior,
 1336    bool,
 1337);
 1338
 1339#[derive(Default)]
 1340struct SelectSyntaxNodeHistory {
 1341    stack: Vec<SelectSyntaxNodeHistoryState>,
 1342    // disable temporarily to allow changing selections without losing the stack
 1343    pub disable_clearing: bool,
 1344}
 1345
 1346impl SelectSyntaxNodeHistory {
 1347    pub fn try_clear(&mut self) {
 1348        if !self.disable_clearing {
 1349            self.stack.clear();
 1350        }
 1351    }
 1352
 1353    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1354        self.stack.push(selection);
 1355    }
 1356
 1357    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1358        self.stack.pop()
 1359    }
 1360}
 1361
 1362enum SelectSyntaxNodeScrollBehavior {
 1363    CursorTop,
 1364    FitSelection,
 1365    CursorBottom,
 1366}
 1367
 1368#[derive(Debug)]
 1369pub(crate) struct NavigationData {
 1370    cursor_anchor: Anchor,
 1371    cursor_position: Point,
 1372    scroll_anchor: ScrollAnchor,
 1373    scroll_top_row: u32,
 1374}
 1375
 1376#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1377pub enum GotoDefinitionKind {
 1378    Symbol,
 1379    Declaration,
 1380    Type,
 1381    Implementation,
 1382}
 1383
 1384#[derive(Debug, Clone)]
 1385enum InlayHintRefreshReason {
 1386    ModifiersChanged(bool),
 1387    Toggle(bool),
 1388    SettingsChange(InlayHintSettings),
 1389    NewLinesShown,
 1390    BufferEdited(HashSet<Arc<Language>>),
 1391    RefreshRequested,
 1392    ExcerptsRemoved(Vec<ExcerptId>),
 1393}
 1394
 1395impl InlayHintRefreshReason {
 1396    fn description(&self) -> &'static str {
 1397        match self {
 1398            Self::ModifiersChanged(_) => "modifiers changed",
 1399            Self::Toggle(_) => "toggle",
 1400            Self::SettingsChange(_) => "settings change",
 1401            Self::NewLinesShown => "new lines shown",
 1402            Self::BufferEdited(_) => "buffer edited",
 1403            Self::RefreshRequested => "refresh requested",
 1404            Self::ExcerptsRemoved(_) => "excerpts removed",
 1405        }
 1406    }
 1407}
 1408
 1409pub enum FormatTarget {
 1410    Buffers,
 1411    Ranges(Vec<Range<MultiBufferPoint>>),
 1412}
 1413
 1414pub(crate) struct FocusedBlock {
 1415    id: BlockId,
 1416    focus_handle: WeakFocusHandle,
 1417}
 1418
 1419#[derive(Clone)]
 1420enum JumpData {
 1421    MultiBufferRow {
 1422        row: MultiBufferRow,
 1423        line_offset_from_top: u32,
 1424    },
 1425    MultiBufferPoint {
 1426        excerpt_id: ExcerptId,
 1427        position: Point,
 1428        anchor: text::Anchor,
 1429        line_offset_from_top: u32,
 1430    },
 1431}
 1432
 1433pub enum MultibufferSelectionMode {
 1434    First,
 1435    All,
 1436}
 1437
 1438#[derive(Clone, Copy, Debug, Default)]
 1439pub struct RewrapOptions {
 1440    pub override_language_settings: bool,
 1441    pub preserve_existing_whitespace: bool,
 1442}
 1443
 1444impl Editor {
 1445    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1446        let buffer = cx.new(|cx| Buffer::local("", cx));
 1447        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1448        Self::new(
 1449            EditorMode::SingleLine { auto_width: false },
 1450            buffer,
 1451            None,
 1452            window,
 1453            cx,
 1454        )
 1455    }
 1456
 1457    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1458        let buffer = cx.new(|cx| Buffer::local("", cx));
 1459        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1460        Self::new(EditorMode::full(), buffer, None, window, cx)
 1461    }
 1462
 1463    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1464        let buffer = cx.new(|cx| Buffer::local("", cx));
 1465        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1466        Self::new(
 1467            EditorMode::SingleLine { auto_width: true },
 1468            buffer,
 1469            None,
 1470            window,
 1471            cx,
 1472        )
 1473    }
 1474
 1475    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1476        let buffer = cx.new(|cx| Buffer::local("", cx));
 1477        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1478        Self::new(
 1479            EditorMode::AutoHeight { max_lines },
 1480            buffer,
 1481            None,
 1482            window,
 1483            cx,
 1484        )
 1485    }
 1486
 1487    pub fn for_buffer(
 1488        buffer: Entity<Buffer>,
 1489        project: Option<Entity<Project>>,
 1490        window: &mut Window,
 1491        cx: &mut Context<Self>,
 1492    ) -> Self {
 1493        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1494        Self::new(EditorMode::full(), buffer, project, window, cx)
 1495    }
 1496
 1497    pub fn for_multibuffer(
 1498        buffer: Entity<MultiBuffer>,
 1499        project: Option<Entity<Project>>,
 1500        window: &mut Window,
 1501        cx: &mut Context<Self>,
 1502    ) -> Self {
 1503        Self::new(EditorMode::full(), buffer, project, window, cx)
 1504    }
 1505
 1506    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1507        let mut clone = Self::new(
 1508            self.mode.clone(),
 1509            self.buffer.clone(),
 1510            self.project.clone(),
 1511            window,
 1512            cx,
 1513        );
 1514        self.display_map.update(cx, |display_map, cx| {
 1515            let snapshot = display_map.snapshot(cx);
 1516            clone.display_map.update(cx, |display_map, cx| {
 1517                display_map.set_state(&snapshot, cx);
 1518            });
 1519        });
 1520        clone.folds_did_change(cx);
 1521        clone.selections.clone_state(&self.selections);
 1522        clone.scroll_manager.clone_state(&self.scroll_manager);
 1523        clone.searchable = self.searchable;
 1524        clone.read_only = self.read_only;
 1525        clone
 1526    }
 1527
 1528    pub fn new(
 1529        mode: EditorMode,
 1530        buffer: Entity<MultiBuffer>,
 1531        project: Option<Entity<Project>>,
 1532        window: &mut Window,
 1533        cx: &mut Context<Self>,
 1534    ) -> Self {
 1535        Editor::new_internal(mode, buffer, project, None, window, cx)
 1536    }
 1537
 1538    fn new_internal(
 1539        mode: EditorMode,
 1540        buffer: Entity<MultiBuffer>,
 1541        project: Option<Entity<Project>>,
 1542        display_map: Option<Entity<DisplayMap>>,
 1543        window: &mut Window,
 1544        cx: &mut Context<Self>,
 1545    ) -> Self {
 1546        debug_assert!(
 1547            display_map.is_none() || mode.is_minimap(),
 1548            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1549        );
 1550
 1551        let full_mode = mode.is_full();
 1552        let diagnostics_max_severity = if full_mode {
 1553            EditorSettings::get_global(cx)
 1554                .diagnostics_max_severity
 1555                .unwrap_or(DiagnosticSeverity::Hint)
 1556        } else {
 1557            DiagnosticSeverity::Off
 1558        };
 1559        let style = window.text_style();
 1560        let font_size = style.font_size.to_pixels(window.rem_size());
 1561        let editor = cx.entity().downgrade();
 1562        let fold_placeholder = FoldPlaceholder {
 1563            constrain_width: true,
 1564            render: Arc::new(move |fold_id, fold_range, cx| {
 1565                let editor = editor.clone();
 1566                div()
 1567                    .id(fold_id)
 1568                    .bg(cx.theme().colors().ghost_element_background)
 1569                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1570                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1571                    .rounded_xs()
 1572                    .size_full()
 1573                    .cursor_pointer()
 1574                    .child("")
 1575                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1576                    .on_click(move |_, _window, cx| {
 1577                        editor
 1578                            .update(cx, |editor, cx| {
 1579                                editor.unfold_ranges(
 1580                                    &[fold_range.start..fold_range.end],
 1581                                    true,
 1582                                    false,
 1583                                    cx,
 1584                                );
 1585                                cx.stop_propagation();
 1586                            })
 1587                            .ok();
 1588                    })
 1589                    .into_any()
 1590            }),
 1591            merge_adjacent: true,
 1592            ..FoldPlaceholder::default()
 1593        };
 1594        let display_map = display_map.unwrap_or_else(|| {
 1595            cx.new(|cx| {
 1596                DisplayMap::new(
 1597                    buffer.clone(),
 1598                    style.font(),
 1599                    font_size,
 1600                    None,
 1601                    FILE_HEADER_HEIGHT,
 1602                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1603                    fold_placeholder,
 1604                    diagnostics_max_severity,
 1605                    cx,
 1606                )
 1607            })
 1608        });
 1609
 1610        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1611
 1612        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1613
 1614        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1615            .then(|| language_settings::SoftWrap::None);
 1616
 1617        let mut project_subscriptions = Vec::new();
 1618        if mode.is_full() {
 1619            if let Some(project) = project.as_ref() {
 1620                project_subscriptions.push(cx.subscribe_in(
 1621                    project,
 1622                    window,
 1623                    |editor, _, event, window, cx| match event {
 1624                        project::Event::RefreshCodeLens => {
 1625                            // we always query lens with actions, without storing them, always refreshing them
 1626                        }
 1627                        project::Event::RefreshInlayHints => {
 1628                            editor
 1629                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1630                        }
 1631                        project::Event::SnippetEdit(id, snippet_edits) => {
 1632                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1633                                let focus_handle = editor.focus_handle(cx);
 1634                                if focus_handle.is_focused(window) {
 1635                                    let snapshot = buffer.read(cx).snapshot();
 1636                                    for (range, snippet) in snippet_edits {
 1637                                        let editor_range =
 1638                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1639                                        editor
 1640                                            .insert_snippet(
 1641                                                &[editor_range],
 1642                                                snippet.clone(),
 1643                                                window,
 1644                                                cx,
 1645                                            )
 1646                                            .ok();
 1647                                    }
 1648                                }
 1649                            }
 1650                        }
 1651                        _ => {}
 1652                    },
 1653                ));
 1654                if let Some(task_inventory) = project
 1655                    .read(cx)
 1656                    .task_store()
 1657                    .read(cx)
 1658                    .task_inventory()
 1659                    .cloned()
 1660                {
 1661                    project_subscriptions.push(cx.observe_in(
 1662                        &task_inventory,
 1663                        window,
 1664                        |editor, _, window, cx| {
 1665                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1666                        },
 1667                    ));
 1668                };
 1669
 1670                project_subscriptions.push(cx.subscribe_in(
 1671                    &project.read(cx).breakpoint_store(),
 1672                    window,
 1673                    |editor, _, event, window, cx| match event {
 1674                        BreakpointStoreEvent::ClearDebugLines => {
 1675                            editor.clear_row_highlights::<ActiveDebugLine>();
 1676                            editor.refresh_inline_values(cx);
 1677                        }
 1678                        BreakpointStoreEvent::SetDebugLine => {
 1679                            if editor.go_to_active_debug_line(window, cx) {
 1680                                cx.stop_propagation();
 1681                            }
 1682
 1683                            editor.refresh_inline_values(cx);
 1684                        }
 1685                        _ => {}
 1686                    },
 1687                ));
 1688            }
 1689        }
 1690
 1691        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1692
 1693        let inlay_hint_settings =
 1694            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1695        let focus_handle = cx.focus_handle();
 1696        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1697            .detach();
 1698        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1699            .detach();
 1700        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1701            .detach();
 1702        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1703            .detach();
 1704
 1705        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1706            Some(false)
 1707        } else {
 1708            None
 1709        };
 1710
 1711        let breakpoint_store = match (&mode, project.as_ref()) {
 1712            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1713            _ => None,
 1714        };
 1715
 1716        let mut code_action_providers = Vec::new();
 1717        let mut load_uncommitted_diff = None;
 1718        if let Some(project) = project.clone() {
 1719            load_uncommitted_diff = Some(
 1720                update_uncommitted_diff_for_buffer(
 1721                    cx.entity(),
 1722                    &project,
 1723                    buffer.read(cx).all_buffers(),
 1724                    buffer.clone(),
 1725                    cx,
 1726                )
 1727                .shared(),
 1728            );
 1729            code_action_providers.push(Rc::new(project) as Rc<_>);
 1730        }
 1731
 1732        let mut this = Self {
 1733            focus_handle,
 1734            show_cursor_when_unfocused: false,
 1735            last_focused_descendant: None,
 1736            buffer: buffer.clone(),
 1737            display_map: display_map.clone(),
 1738            selections,
 1739            scroll_manager: ScrollManager::new(cx),
 1740            columnar_selection_tail: None,
 1741            add_selections_state: None,
 1742            select_next_state: None,
 1743            select_prev_state: None,
 1744            selection_history: SelectionHistory::default(),
 1745            autoclose_regions: Vec::new(),
 1746            snippet_stack: InvalidationStack::default(),
 1747            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1748            ime_transaction: None,
 1749            active_diagnostics: ActiveDiagnostic::None,
 1750            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1751            inline_diagnostics_update: Task::ready(()),
 1752            inline_diagnostics: Vec::new(),
 1753            soft_wrap_mode_override,
 1754            diagnostics_max_severity,
 1755            hard_wrap: None,
 1756            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1757            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1758            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1759            project,
 1760            blink_manager: blink_manager.clone(),
 1761            show_local_selections: true,
 1762            show_scrollbars: full_mode,
 1763            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1764            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1765            show_gutter: mode.is_full(),
 1766            show_line_numbers: None,
 1767            use_relative_line_numbers: None,
 1768            disable_expand_excerpt_buttons: false,
 1769            show_git_diff_gutter: None,
 1770            show_code_actions: None,
 1771            show_runnables: None,
 1772            show_breakpoints: None,
 1773            show_wrap_guides: None,
 1774            show_indent_guides,
 1775            placeholder_text: None,
 1776            highlight_order: 0,
 1777            highlighted_rows: HashMap::default(),
 1778            background_highlights: TreeMap::default(),
 1779            gutter_highlights: TreeMap::default(),
 1780            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1781            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1782            nav_history: None,
 1783            context_menu: RefCell::new(None),
 1784            context_menu_options: None,
 1785            mouse_context_menu: None,
 1786            completion_tasks: Vec::new(),
 1787            inline_blame_popover: None,
 1788            signature_help_state: SignatureHelpState::default(),
 1789            auto_signature_help: None,
 1790            find_all_references_task_sources: Vec::new(),
 1791            next_completion_id: 0,
 1792            next_inlay_id: 0,
 1793            code_action_providers,
 1794            available_code_actions: None,
 1795            code_actions_task: None,
 1796            quick_selection_highlight_task: None,
 1797            debounced_selection_highlight_task: None,
 1798            document_highlights_task: None,
 1799            linked_editing_range_task: None,
 1800            pending_rename: None,
 1801            searchable: true,
 1802            cursor_shape: EditorSettings::get_global(cx)
 1803                .cursor_shape
 1804                .unwrap_or_default(),
 1805            current_line_highlight: None,
 1806            autoindent_mode: Some(AutoindentMode::EachLine),
 1807            collapse_matches: false,
 1808            workspace: None,
 1809            input_enabled: true,
 1810            use_modal_editing: mode.is_full(),
 1811            read_only: mode.is_minimap(),
 1812            use_autoclose: true,
 1813            use_auto_surround: true,
 1814            auto_replace_emoji_shortcode: false,
 1815            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1816            leader_id: None,
 1817            remote_id: None,
 1818            hover_state: HoverState::default(),
 1819            pending_mouse_down: None,
 1820            hovered_link_state: None,
 1821            edit_prediction_provider: None,
 1822            active_inline_completion: None,
 1823            stale_inline_completion_in_menu: None,
 1824            edit_prediction_preview: EditPredictionPreview::Inactive {
 1825                released_too_fast: false,
 1826            },
 1827            inline_diagnostics_enabled: mode.is_full(),
 1828            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1829            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1830
 1831            gutter_hovered: false,
 1832            pixel_position_of_newest_cursor: None,
 1833            last_bounds: None,
 1834            last_position_map: None,
 1835            expect_bounds_change: None,
 1836            gutter_dimensions: GutterDimensions::default(),
 1837            style: None,
 1838            show_cursor_names: false,
 1839            hovered_cursors: HashMap::default(),
 1840            next_editor_action_id: EditorActionId::default(),
 1841            editor_actions: Rc::default(),
 1842            inline_completions_hidden_for_vim_mode: false,
 1843            show_inline_completions_override: None,
 1844            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1845            edit_prediction_settings: EditPredictionSettings::Disabled,
 1846            edit_prediction_indent_conflict: false,
 1847            edit_prediction_requires_modifier_in_indent_conflict: true,
 1848            custom_context_menu: None,
 1849            show_git_blame_gutter: false,
 1850            show_git_blame_inline: false,
 1851            show_selection_menu: None,
 1852            show_git_blame_inline_delay_task: None,
 1853            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1854            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1855            serialize_dirty_buffers: !mode.is_minimap()
 1856                && ProjectSettings::get_global(cx)
 1857                    .session
 1858                    .restore_unsaved_buffers,
 1859            blame: None,
 1860            blame_subscription: None,
 1861            tasks: BTreeMap::default(),
 1862
 1863            breakpoint_store,
 1864            gutter_breakpoint_indicator: (None, None),
 1865            _subscriptions: vec![
 1866                cx.observe(&buffer, Self::on_buffer_changed),
 1867                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1868                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1869                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1870                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1871                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1872                cx.observe_window_activation(window, |editor, window, cx| {
 1873                    let active = window.is_window_active();
 1874                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1875                        if active {
 1876                            blink_manager.enable(cx);
 1877                        } else {
 1878                            blink_manager.disable(cx);
 1879                        }
 1880                    });
 1881                }),
 1882            ],
 1883            tasks_update_task: None,
 1884            linked_edit_ranges: Default::default(),
 1885            in_project_search: false,
 1886            previous_search_ranges: None,
 1887            breadcrumb_header: None,
 1888            focused_block: None,
 1889            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1890            addons: HashMap::default(),
 1891            registered_buffers: HashMap::default(),
 1892            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1893            selection_mark_mode: false,
 1894            toggle_fold_multiple_buffers: Task::ready(()),
 1895            serialize_selections: Task::ready(()),
 1896            serialize_folds: Task::ready(()),
 1897            text_style_refinement: None,
 1898            load_diff_task: load_uncommitted_diff,
 1899            temporary_diff_override: false,
 1900            mouse_cursor_hidden: false,
 1901            minimap: None,
 1902            hide_mouse_mode: EditorSettings::get_global(cx)
 1903                .hide_mouse
 1904                .unwrap_or_default(),
 1905            change_list: ChangeList::new(),
 1906            mode,
 1907        };
 1908        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1909            this._subscriptions
 1910                .push(cx.observe(breakpoints, |_, _, cx| {
 1911                    cx.notify();
 1912                }));
 1913        }
 1914        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1915        this._subscriptions.extend(project_subscriptions);
 1916
 1917        this._subscriptions.push(cx.subscribe_in(
 1918            &cx.entity(),
 1919            window,
 1920            |editor, _, e: &EditorEvent, window, cx| match e {
 1921                EditorEvent::ScrollPositionChanged { local, .. } => {
 1922                    if *local {
 1923                        let new_anchor = editor.scroll_manager.anchor();
 1924                        let snapshot = editor.snapshot(window, cx);
 1925                        editor.update_restoration_data(cx, move |data| {
 1926                            data.scroll_position = (
 1927                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1928                                new_anchor.offset,
 1929                            );
 1930                        });
 1931                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1932                        editor.inline_blame_popover.take();
 1933                    }
 1934                }
 1935                EditorEvent::Edited { .. } => {
 1936                    if !vim_enabled(cx) {
 1937                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1938                        let pop_state = editor
 1939                            .change_list
 1940                            .last()
 1941                            .map(|previous| {
 1942                                previous.len() == selections.len()
 1943                                    && previous.iter().enumerate().all(|(ix, p)| {
 1944                                        p.to_display_point(&map).row()
 1945                                            == selections[ix].head().row()
 1946                                    })
 1947                            })
 1948                            .unwrap_or(false);
 1949                        let new_positions = selections
 1950                            .into_iter()
 1951                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1952                            .collect();
 1953                        editor
 1954                            .change_list
 1955                            .push_to_change_list(pop_state, new_positions);
 1956                    }
 1957                }
 1958                _ => (),
 1959            },
 1960        ));
 1961
 1962        if let Some(dap_store) = this
 1963            .project
 1964            .as_ref()
 1965            .map(|project| project.read(cx).dap_store())
 1966        {
 1967            let weak_editor = cx.weak_entity();
 1968
 1969            this._subscriptions
 1970                .push(
 1971                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1972                        let session_entity = cx.entity();
 1973                        weak_editor
 1974                            .update(cx, |editor, cx| {
 1975                                editor._subscriptions.push(
 1976                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1977                                );
 1978                            })
 1979                            .ok();
 1980                    }),
 1981                );
 1982
 1983            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1984                this._subscriptions
 1985                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1986            }
 1987        }
 1988
 1989        this.end_selection(window, cx);
 1990        this.scroll_manager.show_scrollbars(window, cx);
 1991        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1992
 1993        if full_mode {
 1994            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1995            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1996
 1997            if this.git_blame_inline_enabled {
 1998                this.start_git_blame_inline(false, window, cx);
 1999            }
 2000
 2001            this.go_to_active_debug_line(window, cx);
 2002
 2003            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2004                if let Some(project) = this.project.as_ref() {
 2005                    let handle = project.update(cx, |project, cx| {
 2006                        project.register_buffer_with_language_servers(&buffer, cx)
 2007                    });
 2008                    this.registered_buffers
 2009                        .insert(buffer.read(cx).remote_id(), handle);
 2010                }
 2011            }
 2012
 2013            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2014        }
 2015
 2016        this.report_editor_event("Editor Opened", None, cx);
 2017        this
 2018    }
 2019
 2020    pub fn deploy_mouse_context_menu(
 2021        &mut self,
 2022        position: gpui::Point<Pixels>,
 2023        context_menu: Entity<ContextMenu>,
 2024        window: &mut Window,
 2025        cx: &mut Context<Self>,
 2026    ) {
 2027        self.mouse_context_menu = Some(MouseContextMenu::new(
 2028            self,
 2029            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2030            context_menu,
 2031            window,
 2032            cx,
 2033        ));
 2034    }
 2035
 2036    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2037        self.mouse_context_menu
 2038            .as_ref()
 2039            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2040    }
 2041
 2042    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2043        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2044    }
 2045
 2046    fn key_context_internal(
 2047        &self,
 2048        has_active_edit_prediction: bool,
 2049        window: &Window,
 2050        cx: &App,
 2051    ) -> KeyContext {
 2052        let mut key_context = KeyContext::new_with_defaults();
 2053        key_context.add("Editor");
 2054        let mode = match self.mode {
 2055            EditorMode::SingleLine { .. } => "single_line",
 2056            EditorMode::AutoHeight { .. } => "auto_height",
 2057            EditorMode::Minimap { .. } => "minimap",
 2058            EditorMode::Full { .. } => "full",
 2059        };
 2060
 2061        if EditorSettings::jupyter_enabled(cx) {
 2062            key_context.add("jupyter");
 2063        }
 2064
 2065        key_context.set("mode", mode);
 2066        if self.pending_rename.is_some() {
 2067            key_context.add("renaming");
 2068        }
 2069
 2070        match self.context_menu.borrow().as_ref() {
 2071            Some(CodeContextMenu::Completions(_)) => {
 2072                key_context.add("menu");
 2073                key_context.add("showing_completions");
 2074            }
 2075            Some(CodeContextMenu::CodeActions(_)) => {
 2076                key_context.add("menu");
 2077                key_context.add("showing_code_actions")
 2078            }
 2079            None => {}
 2080        }
 2081
 2082        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2083        if !self.focus_handle(cx).contains_focused(window, cx)
 2084            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2085        {
 2086            for addon in self.addons.values() {
 2087                addon.extend_key_context(&mut key_context, cx)
 2088            }
 2089        }
 2090
 2091        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2092            if let Some(extension) = singleton_buffer
 2093                .read(cx)
 2094                .file()
 2095                .and_then(|file| file.path().extension()?.to_str())
 2096            {
 2097                key_context.set("extension", extension.to_string());
 2098            }
 2099        } else {
 2100            key_context.add("multibuffer");
 2101        }
 2102
 2103        if has_active_edit_prediction {
 2104            if self.edit_prediction_in_conflict() {
 2105                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2106            } else {
 2107                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2108                key_context.add("copilot_suggestion");
 2109            }
 2110        }
 2111
 2112        if self.selection_mark_mode {
 2113            key_context.add("selection_mode");
 2114        }
 2115
 2116        key_context
 2117    }
 2118
 2119    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2120        self.mouse_cursor_hidden = match origin {
 2121            HideMouseCursorOrigin::TypingAction => {
 2122                matches!(
 2123                    self.hide_mouse_mode,
 2124                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2125                )
 2126            }
 2127            HideMouseCursorOrigin::MovementAction => {
 2128                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2129            }
 2130        };
 2131    }
 2132
 2133    pub fn edit_prediction_in_conflict(&self) -> bool {
 2134        if !self.show_edit_predictions_in_menu() {
 2135            return false;
 2136        }
 2137
 2138        let showing_completions = self
 2139            .context_menu
 2140            .borrow()
 2141            .as_ref()
 2142            .map_or(false, |context| {
 2143                matches!(context, CodeContextMenu::Completions(_))
 2144            });
 2145
 2146        showing_completions
 2147            || self.edit_prediction_requires_modifier()
 2148            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2149            // bindings to insert tab characters.
 2150            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2151    }
 2152
 2153    pub fn accept_edit_prediction_keybind(
 2154        &self,
 2155        window: &Window,
 2156        cx: &App,
 2157    ) -> AcceptEditPredictionBinding {
 2158        let key_context = self.key_context_internal(true, window, cx);
 2159        let in_conflict = self.edit_prediction_in_conflict();
 2160
 2161        AcceptEditPredictionBinding(
 2162            window
 2163                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2164                .into_iter()
 2165                .filter(|binding| {
 2166                    !in_conflict
 2167                        || binding
 2168                            .keystrokes()
 2169                            .first()
 2170                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2171                })
 2172                .rev()
 2173                .min_by_key(|binding| {
 2174                    binding
 2175                        .keystrokes()
 2176                        .first()
 2177                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2178                }),
 2179        )
 2180    }
 2181
 2182    pub fn new_file(
 2183        workspace: &mut Workspace,
 2184        _: &workspace::NewFile,
 2185        window: &mut Window,
 2186        cx: &mut Context<Workspace>,
 2187    ) {
 2188        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2189            "Failed to create buffer",
 2190            window,
 2191            cx,
 2192            |e, _, _| match e.error_code() {
 2193                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2194                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2195                e.error_tag("required").unwrap_or("the latest version")
 2196            )),
 2197                _ => None,
 2198            },
 2199        );
 2200    }
 2201
 2202    pub fn new_in_workspace(
 2203        workspace: &mut Workspace,
 2204        window: &mut Window,
 2205        cx: &mut Context<Workspace>,
 2206    ) -> Task<Result<Entity<Editor>>> {
 2207        let project = workspace.project().clone();
 2208        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2209
 2210        cx.spawn_in(window, async move |workspace, cx| {
 2211            let buffer = create.await?;
 2212            workspace.update_in(cx, |workspace, window, cx| {
 2213                let editor =
 2214                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2215                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2216                editor
 2217            })
 2218        })
 2219    }
 2220
 2221    fn new_file_vertical(
 2222        workspace: &mut Workspace,
 2223        _: &workspace::NewFileSplitVertical,
 2224        window: &mut Window,
 2225        cx: &mut Context<Workspace>,
 2226    ) {
 2227        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2228    }
 2229
 2230    fn new_file_horizontal(
 2231        workspace: &mut Workspace,
 2232        _: &workspace::NewFileSplitHorizontal,
 2233        window: &mut Window,
 2234        cx: &mut Context<Workspace>,
 2235    ) {
 2236        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2237    }
 2238
 2239    fn new_file_in_direction(
 2240        workspace: &mut Workspace,
 2241        direction: SplitDirection,
 2242        window: &mut Window,
 2243        cx: &mut Context<Workspace>,
 2244    ) {
 2245        let project = workspace.project().clone();
 2246        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2247
 2248        cx.spawn_in(window, async move |workspace, cx| {
 2249            let buffer = create.await?;
 2250            workspace.update_in(cx, move |workspace, window, cx| {
 2251                workspace.split_item(
 2252                    direction,
 2253                    Box::new(
 2254                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2255                    ),
 2256                    window,
 2257                    cx,
 2258                )
 2259            })?;
 2260            anyhow::Ok(())
 2261        })
 2262        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2263            match e.error_code() {
 2264                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2265                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2266                e.error_tag("required").unwrap_or("the latest version")
 2267            )),
 2268                _ => None,
 2269            }
 2270        });
 2271    }
 2272
 2273    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2274        self.leader_id
 2275    }
 2276
 2277    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2278        &self.buffer
 2279    }
 2280
 2281    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2282        self.workspace.as_ref()?.0.upgrade()
 2283    }
 2284
 2285    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2286        self.buffer().read(cx).title(cx)
 2287    }
 2288
 2289    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2290        let git_blame_gutter_max_author_length = self
 2291            .render_git_blame_gutter(cx)
 2292            .then(|| {
 2293                if let Some(blame) = self.blame.as_ref() {
 2294                    let max_author_length =
 2295                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2296                    Some(max_author_length)
 2297                } else {
 2298                    None
 2299                }
 2300            })
 2301            .flatten();
 2302
 2303        EditorSnapshot {
 2304            mode: self.mode.clone(),
 2305            show_gutter: self.show_gutter,
 2306            show_line_numbers: self.show_line_numbers,
 2307            show_git_diff_gutter: self.show_git_diff_gutter,
 2308            show_runnables: self.show_runnables,
 2309            show_breakpoints: self.show_breakpoints,
 2310            git_blame_gutter_max_author_length,
 2311            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2312            scroll_anchor: self.scroll_manager.anchor(),
 2313            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2314            placeholder_text: self.placeholder_text.clone(),
 2315            is_focused: self.focus_handle.is_focused(window),
 2316            current_line_highlight: self
 2317                .current_line_highlight
 2318                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2319            gutter_hovered: self.gutter_hovered,
 2320        }
 2321    }
 2322
 2323    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2324        self.buffer.read(cx).language_at(point, cx)
 2325    }
 2326
 2327    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2328        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2329    }
 2330
 2331    pub fn active_excerpt(
 2332        &self,
 2333        cx: &App,
 2334    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2335        self.buffer
 2336            .read(cx)
 2337            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2338    }
 2339
 2340    pub fn mode(&self) -> &EditorMode {
 2341        &self.mode
 2342    }
 2343
 2344    pub fn set_mode(&mut self, mode: EditorMode) {
 2345        self.mode = mode;
 2346    }
 2347
 2348    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2349        self.collaboration_hub.as_deref()
 2350    }
 2351
 2352    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2353        self.collaboration_hub = Some(hub);
 2354    }
 2355
 2356    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2357        self.in_project_search = in_project_search;
 2358    }
 2359
 2360    pub fn set_custom_context_menu(
 2361        &mut self,
 2362        f: impl 'static
 2363        + Fn(
 2364            &mut Self,
 2365            DisplayPoint,
 2366            &mut Window,
 2367            &mut Context<Self>,
 2368        ) -> Option<Entity<ui::ContextMenu>>,
 2369    ) {
 2370        self.custom_context_menu = Some(Box::new(f))
 2371    }
 2372
 2373    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2374        self.completion_provider = provider;
 2375    }
 2376
 2377    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2378        self.semantics_provider.clone()
 2379    }
 2380
 2381    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2382        self.semantics_provider = provider;
 2383    }
 2384
 2385    pub fn set_edit_prediction_provider<T>(
 2386        &mut self,
 2387        provider: Option<Entity<T>>,
 2388        window: &mut Window,
 2389        cx: &mut Context<Self>,
 2390    ) where
 2391        T: EditPredictionProvider,
 2392    {
 2393        self.edit_prediction_provider =
 2394            provider.map(|provider| RegisteredInlineCompletionProvider {
 2395                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2396                    if this.focus_handle.is_focused(window) {
 2397                        this.update_visible_inline_completion(window, cx);
 2398                    }
 2399                }),
 2400                provider: Arc::new(provider),
 2401            });
 2402        self.update_edit_prediction_settings(cx);
 2403        self.refresh_inline_completion(false, false, window, cx);
 2404    }
 2405
 2406    pub fn placeholder_text(&self) -> Option<&str> {
 2407        self.placeholder_text.as_deref()
 2408    }
 2409
 2410    pub fn set_placeholder_text(
 2411        &mut self,
 2412        placeholder_text: impl Into<Arc<str>>,
 2413        cx: &mut Context<Self>,
 2414    ) {
 2415        let placeholder_text = Some(placeholder_text.into());
 2416        if self.placeholder_text != placeholder_text {
 2417            self.placeholder_text = placeholder_text;
 2418            cx.notify();
 2419        }
 2420    }
 2421
 2422    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2423        self.cursor_shape = cursor_shape;
 2424
 2425        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2426        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2427
 2428        cx.notify();
 2429    }
 2430
 2431    pub fn set_current_line_highlight(
 2432        &mut self,
 2433        current_line_highlight: Option<CurrentLineHighlight>,
 2434    ) {
 2435        self.current_line_highlight = current_line_highlight;
 2436    }
 2437
 2438    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2439        self.collapse_matches = collapse_matches;
 2440    }
 2441
 2442    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2443        let buffers = self.buffer.read(cx).all_buffers();
 2444        let Some(project) = self.project.as_ref() else {
 2445            return;
 2446        };
 2447        project.update(cx, |project, cx| {
 2448            for buffer in buffers {
 2449                self.registered_buffers
 2450                    .entry(buffer.read(cx).remote_id())
 2451                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2452            }
 2453        })
 2454    }
 2455
 2456    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2457        if self.collapse_matches {
 2458            return range.start..range.start;
 2459        }
 2460        range.clone()
 2461    }
 2462
 2463    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2464        if self.display_map.read(cx).clip_at_line_ends != clip {
 2465            self.display_map
 2466                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2467        }
 2468    }
 2469
 2470    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2471        self.input_enabled = input_enabled;
 2472    }
 2473
 2474    pub fn set_inline_completions_hidden_for_vim_mode(
 2475        &mut self,
 2476        hidden: bool,
 2477        window: &mut Window,
 2478        cx: &mut Context<Self>,
 2479    ) {
 2480        if hidden != self.inline_completions_hidden_for_vim_mode {
 2481            self.inline_completions_hidden_for_vim_mode = hidden;
 2482            if hidden {
 2483                self.update_visible_inline_completion(window, cx);
 2484            } else {
 2485                self.refresh_inline_completion(true, false, window, cx);
 2486            }
 2487        }
 2488    }
 2489
 2490    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2491        self.menu_inline_completions_policy = value;
 2492    }
 2493
 2494    pub fn set_autoindent(&mut self, autoindent: bool) {
 2495        if autoindent {
 2496            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2497        } else {
 2498            self.autoindent_mode = None;
 2499        }
 2500    }
 2501
 2502    pub fn read_only(&self, cx: &App) -> bool {
 2503        self.read_only || self.buffer.read(cx).read_only()
 2504    }
 2505
 2506    pub fn set_read_only(&mut self, read_only: bool) {
 2507        self.read_only = read_only;
 2508    }
 2509
 2510    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2511        self.use_autoclose = autoclose;
 2512    }
 2513
 2514    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2515        self.use_auto_surround = auto_surround;
 2516    }
 2517
 2518    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2519        self.auto_replace_emoji_shortcode = auto_replace;
 2520    }
 2521
 2522    pub fn toggle_edit_predictions(
 2523        &mut self,
 2524        _: &ToggleEditPrediction,
 2525        window: &mut Window,
 2526        cx: &mut Context<Self>,
 2527    ) {
 2528        if self.show_inline_completions_override.is_some() {
 2529            self.set_show_edit_predictions(None, window, cx);
 2530        } else {
 2531            let show_edit_predictions = !self.edit_predictions_enabled();
 2532            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2533        }
 2534    }
 2535
 2536    pub fn set_show_edit_predictions(
 2537        &mut self,
 2538        show_edit_predictions: Option<bool>,
 2539        window: &mut Window,
 2540        cx: &mut Context<Self>,
 2541    ) {
 2542        self.show_inline_completions_override = show_edit_predictions;
 2543        self.update_edit_prediction_settings(cx);
 2544
 2545        if let Some(false) = show_edit_predictions {
 2546            self.discard_inline_completion(false, cx);
 2547        } else {
 2548            self.refresh_inline_completion(false, true, window, cx);
 2549        }
 2550    }
 2551
 2552    fn inline_completions_disabled_in_scope(
 2553        &self,
 2554        buffer: &Entity<Buffer>,
 2555        buffer_position: language::Anchor,
 2556        cx: &App,
 2557    ) -> bool {
 2558        let snapshot = buffer.read(cx).snapshot();
 2559        let settings = snapshot.settings_at(buffer_position, cx);
 2560
 2561        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2562            return false;
 2563        };
 2564
 2565        scope.override_name().map_or(false, |scope_name| {
 2566            settings
 2567                .edit_predictions_disabled_in
 2568                .iter()
 2569                .any(|s| s == scope_name)
 2570        })
 2571    }
 2572
 2573    pub fn set_use_modal_editing(&mut self, to: bool) {
 2574        self.use_modal_editing = to;
 2575    }
 2576
 2577    pub fn use_modal_editing(&self) -> bool {
 2578        self.use_modal_editing
 2579    }
 2580
 2581    fn selections_did_change(
 2582        &mut self,
 2583        local: bool,
 2584        old_cursor_position: &Anchor,
 2585        show_completions: bool,
 2586        window: &mut Window,
 2587        cx: &mut Context<Self>,
 2588    ) {
 2589        window.invalidate_character_coordinates();
 2590
 2591        // Copy selections to primary selection buffer
 2592        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2593        if local {
 2594            let selections = self.selections.all::<usize>(cx);
 2595            let buffer_handle = self.buffer.read(cx).read(cx);
 2596
 2597            let mut text = String::new();
 2598            for (index, selection) in selections.iter().enumerate() {
 2599                let text_for_selection = buffer_handle
 2600                    .text_for_range(selection.start..selection.end)
 2601                    .collect::<String>();
 2602
 2603                text.push_str(&text_for_selection);
 2604                if index != selections.len() - 1 {
 2605                    text.push('\n');
 2606                }
 2607            }
 2608
 2609            if !text.is_empty() {
 2610                cx.write_to_primary(ClipboardItem::new_string(text));
 2611            }
 2612        }
 2613
 2614        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2615            self.buffer.update(cx, |buffer, cx| {
 2616                buffer.set_active_selections(
 2617                    &self.selections.disjoint_anchors(),
 2618                    self.selections.line_mode,
 2619                    self.cursor_shape,
 2620                    cx,
 2621                )
 2622            });
 2623        }
 2624        let display_map = self
 2625            .display_map
 2626            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2627        let buffer = &display_map.buffer_snapshot;
 2628        self.add_selections_state = None;
 2629        self.select_next_state = None;
 2630        self.select_prev_state = None;
 2631        self.select_syntax_node_history.try_clear();
 2632        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2633        self.snippet_stack
 2634            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2635        self.take_rename(false, window, cx);
 2636
 2637        let new_cursor_position = self.selections.newest_anchor().head();
 2638
 2639        self.push_to_nav_history(
 2640            *old_cursor_position,
 2641            Some(new_cursor_position.to_point(buffer)),
 2642            false,
 2643            cx,
 2644        );
 2645
 2646        if local {
 2647            let new_cursor_position = self.selections.newest_anchor().head();
 2648            let mut context_menu = self.context_menu.borrow_mut();
 2649            let completion_menu = match context_menu.as_ref() {
 2650                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2651                _ => {
 2652                    *context_menu = None;
 2653                    None
 2654                }
 2655            };
 2656            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2657                if !self.registered_buffers.contains_key(&buffer_id) {
 2658                    if let Some(project) = self.project.as_ref() {
 2659                        project.update(cx, |project, cx| {
 2660                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2661                                return;
 2662                            };
 2663                            self.registered_buffers.insert(
 2664                                buffer_id,
 2665                                project.register_buffer_with_language_servers(&buffer, cx),
 2666                            );
 2667                        })
 2668                    }
 2669                }
 2670            }
 2671
 2672            if let Some(completion_menu) = completion_menu {
 2673                let cursor_position = new_cursor_position.to_offset(buffer);
 2674                let (word_range, kind) =
 2675                    buffer.surrounding_word(completion_menu.initial_position, true);
 2676                if kind == Some(CharKind::Word)
 2677                    && word_range.to_inclusive().contains(&cursor_position)
 2678                {
 2679                    let mut completion_menu = completion_menu.clone();
 2680                    drop(context_menu);
 2681
 2682                    let query = Self::completion_query(buffer, cursor_position);
 2683                    cx.spawn(async move |this, cx| {
 2684                        completion_menu
 2685                            .filter(query.as_deref(), cx.background_executor().clone())
 2686                            .await;
 2687
 2688                        this.update(cx, |this, cx| {
 2689                            let mut context_menu = this.context_menu.borrow_mut();
 2690                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2691                            else {
 2692                                return;
 2693                            };
 2694
 2695                            if menu.id > completion_menu.id {
 2696                                return;
 2697                            }
 2698
 2699                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2700                            drop(context_menu);
 2701                            cx.notify();
 2702                        })
 2703                    })
 2704                    .detach();
 2705
 2706                    if show_completions {
 2707                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2708                    }
 2709                } else {
 2710                    drop(context_menu);
 2711                    self.hide_context_menu(window, cx);
 2712                }
 2713            } else {
 2714                drop(context_menu);
 2715            }
 2716
 2717            hide_hover(self, cx);
 2718
 2719            if old_cursor_position.to_display_point(&display_map).row()
 2720                != new_cursor_position.to_display_point(&display_map).row()
 2721            {
 2722                self.available_code_actions.take();
 2723            }
 2724            self.refresh_code_actions(window, cx);
 2725            self.refresh_document_highlights(cx);
 2726            self.refresh_selected_text_highlights(false, window, cx);
 2727            refresh_matching_bracket_highlights(self, window, cx);
 2728            self.update_visible_inline_completion(window, cx);
 2729            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2730            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2731            self.inline_blame_popover.take();
 2732            if self.git_blame_inline_enabled {
 2733                self.start_inline_blame_timer(window, cx);
 2734            }
 2735        }
 2736
 2737        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2738        cx.emit(EditorEvent::SelectionsChanged { local });
 2739
 2740        let selections = &self.selections.disjoint;
 2741        if selections.len() == 1 {
 2742            cx.emit(SearchEvent::ActiveMatchChanged)
 2743        }
 2744        if local {
 2745            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2746                let inmemory_selections = selections
 2747                    .iter()
 2748                    .map(|s| {
 2749                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2750                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2751                    })
 2752                    .collect();
 2753                self.update_restoration_data(cx, |data| {
 2754                    data.selections = inmemory_selections;
 2755                });
 2756
 2757                if WorkspaceSettings::get(None, cx).restore_on_startup
 2758                    != RestoreOnStartupBehavior::None
 2759                {
 2760                    if let Some(workspace_id) =
 2761                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2762                    {
 2763                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2764                        let selections = selections.clone();
 2765                        let background_executor = cx.background_executor().clone();
 2766                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2767                        self.serialize_selections = cx.background_spawn(async move {
 2768                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2769                    let db_selections = selections
 2770                        .iter()
 2771                        .map(|selection| {
 2772                            (
 2773                                selection.start.to_offset(&snapshot),
 2774                                selection.end.to_offset(&snapshot),
 2775                            )
 2776                        })
 2777                        .collect();
 2778
 2779                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2780                        .await
 2781                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2782                        .log_err();
 2783                });
 2784                    }
 2785                }
 2786            }
 2787        }
 2788
 2789        cx.notify();
 2790    }
 2791
 2792    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2793        use text::ToOffset as _;
 2794        use text::ToPoint as _;
 2795
 2796        if self.mode.is_minimap()
 2797            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2798        {
 2799            return;
 2800        }
 2801
 2802        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2803            return;
 2804        };
 2805
 2806        let snapshot = singleton.read(cx).snapshot();
 2807        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2808            let display_snapshot = display_map.snapshot(cx);
 2809
 2810            display_snapshot
 2811                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2812                .map(|fold| {
 2813                    fold.range.start.text_anchor.to_point(&snapshot)
 2814                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2815                })
 2816                .collect()
 2817        });
 2818        self.update_restoration_data(cx, |data| {
 2819            data.folds = inmemory_folds;
 2820        });
 2821
 2822        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2823            return;
 2824        };
 2825        let background_executor = cx.background_executor().clone();
 2826        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2827        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2828            display_map
 2829                .snapshot(cx)
 2830                .folds_in_range(0..snapshot.len())
 2831                .map(|fold| {
 2832                    (
 2833                        fold.range.start.text_anchor.to_offset(&snapshot),
 2834                        fold.range.end.text_anchor.to_offset(&snapshot),
 2835                    )
 2836                })
 2837                .collect()
 2838        });
 2839        self.serialize_folds = cx.background_spawn(async move {
 2840            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2841            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2842                .await
 2843                .with_context(|| {
 2844                    format!(
 2845                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2846                    )
 2847                })
 2848                .log_err();
 2849        });
 2850    }
 2851
 2852    pub fn sync_selections(
 2853        &mut self,
 2854        other: Entity<Editor>,
 2855        cx: &mut Context<Self>,
 2856    ) -> gpui::Subscription {
 2857        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2858        self.selections.change_with(cx, |selections| {
 2859            selections.select_anchors(other_selections);
 2860        });
 2861
 2862        let other_subscription =
 2863            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2864                EditorEvent::SelectionsChanged { local: true } => {
 2865                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2866                    if other_selections.is_empty() {
 2867                        return;
 2868                    }
 2869                    this.selections.change_with(cx, |selections| {
 2870                        selections.select_anchors(other_selections);
 2871                    });
 2872                }
 2873                _ => {}
 2874            });
 2875
 2876        let this_subscription =
 2877            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2878                EditorEvent::SelectionsChanged { local: true } => {
 2879                    let these_selections = this.selections.disjoint.to_vec();
 2880                    if these_selections.is_empty() {
 2881                        return;
 2882                    }
 2883                    other.update(cx, |other_editor, cx| {
 2884                        other_editor.selections.change_with(cx, |selections| {
 2885                            selections.select_anchors(these_selections);
 2886                        })
 2887                    });
 2888                }
 2889                _ => {}
 2890            });
 2891
 2892        Subscription::join(other_subscription, this_subscription)
 2893    }
 2894
 2895    pub fn change_selections<R>(
 2896        &mut self,
 2897        autoscroll: Option<Autoscroll>,
 2898        window: &mut Window,
 2899        cx: &mut Context<Self>,
 2900        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2901    ) -> R {
 2902        self.change_selections_inner(autoscroll, true, window, cx, change)
 2903    }
 2904
 2905    fn change_selections_inner<R>(
 2906        &mut self,
 2907        autoscroll: Option<Autoscroll>,
 2908        request_completions: bool,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2912    ) -> R {
 2913        let old_cursor_position = self.selections.newest_anchor().head();
 2914        self.push_to_selection_history();
 2915
 2916        let (changed, result) = self.selections.change_with(cx, change);
 2917
 2918        if changed {
 2919            if let Some(autoscroll) = autoscroll {
 2920                self.request_autoscroll(autoscroll, cx);
 2921            }
 2922            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2923
 2924            if self.should_open_signature_help_automatically(
 2925                &old_cursor_position,
 2926                self.signature_help_state.backspace_pressed(),
 2927                cx,
 2928            ) {
 2929                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2930            }
 2931            self.signature_help_state.set_backspace_pressed(false);
 2932        }
 2933
 2934        result
 2935    }
 2936
 2937    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2938    where
 2939        I: IntoIterator<Item = (Range<S>, T)>,
 2940        S: ToOffset,
 2941        T: Into<Arc<str>>,
 2942    {
 2943        if self.read_only(cx) {
 2944            return;
 2945        }
 2946
 2947        self.buffer
 2948            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2949    }
 2950
 2951    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2952    where
 2953        I: IntoIterator<Item = (Range<S>, T)>,
 2954        S: ToOffset,
 2955        T: Into<Arc<str>>,
 2956    {
 2957        if self.read_only(cx) {
 2958            return;
 2959        }
 2960
 2961        self.buffer.update(cx, |buffer, cx| {
 2962            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2963        });
 2964    }
 2965
 2966    pub fn edit_with_block_indent<I, S, T>(
 2967        &mut self,
 2968        edits: I,
 2969        original_indent_columns: Vec<Option<u32>>,
 2970        cx: &mut Context<Self>,
 2971    ) where
 2972        I: IntoIterator<Item = (Range<S>, T)>,
 2973        S: ToOffset,
 2974        T: Into<Arc<str>>,
 2975    {
 2976        if self.read_only(cx) {
 2977            return;
 2978        }
 2979
 2980        self.buffer.update(cx, |buffer, cx| {
 2981            buffer.edit(
 2982                edits,
 2983                Some(AutoindentMode::Block {
 2984                    original_indent_columns,
 2985                }),
 2986                cx,
 2987            )
 2988        });
 2989    }
 2990
 2991    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2992        self.hide_context_menu(window, cx);
 2993
 2994        match phase {
 2995            SelectPhase::Begin {
 2996                position,
 2997                add,
 2998                click_count,
 2999            } => self.begin_selection(position, add, click_count, window, cx),
 3000            SelectPhase::BeginColumnar {
 3001                position,
 3002                goal_column,
 3003                reset,
 3004            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3005            SelectPhase::Extend {
 3006                position,
 3007                click_count,
 3008            } => self.extend_selection(position, click_count, window, cx),
 3009            SelectPhase::Update {
 3010                position,
 3011                goal_column,
 3012                scroll_delta,
 3013            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3014            SelectPhase::End => self.end_selection(window, cx),
 3015        }
 3016    }
 3017
 3018    fn extend_selection(
 3019        &mut self,
 3020        position: DisplayPoint,
 3021        click_count: usize,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024    ) {
 3025        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3026        let tail = self.selections.newest::<usize>(cx).tail();
 3027        self.begin_selection(position, false, click_count, window, cx);
 3028
 3029        let position = position.to_offset(&display_map, Bias::Left);
 3030        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3031
 3032        let mut pending_selection = self
 3033            .selections
 3034            .pending_anchor()
 3035            .expect("extend_selection not called with pending selection");
 3036        if position >= tail {
 3037            pending_selection.start = tail_anchor;
 3038        } else {
 3039            pending_selection.end = tail_anchor;
 3040            pending_selection.reversed = true;
 3041        }
 3042
 3043        let mut pending_mode = self.selections.pending_mode().unwrap();
 3044        match &mut pending_mode {
 3045            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3046            _ => {}
 3047        }
 3048
 3049        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3050
 3051        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3052            s.set_pending(pending_selection, pending_mode)
 3053        });
 3054    }
 3055
 3056    fn begin_selection(
 3057        &mut self,
 3058        position: DisplayPoint,
 3059        add: bool,
 3060        click_count: usize,
 3061        window: &mut Window,
 3062        cx: &mut Context<Self>,
 3063    ) {
 3064        if !self.focus_handle.is_focused(window) {
 3065            self.last_focused_descendant = None;
 3066            window.focus(&self.focus_handle);
 3067        }
 3068
 3069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3070        let buffer = &display_map.buffer_snapshot;
 3071        let position = display_map.clip_point(position, Bias::Left);
 3072
 3073        let start;
 3074        let end;
 3075        let mode;
 3076        let mut auto_scroll;
 3077        match click_count {
 3078            1 => {
 3079                start = buffer.anchor_before(position.to_point(&display_map));
 3080                end = start;
 3081                mode = SelectMode::Character;
 3082                auto_scroll = true;
 3083            }
 3084            2 => {
 3085                let range = movement::surrounding_word(&display_map, position);
 3086                start = buffer.anchor_before(range.start.to_point(&display_map));
 3087                end = buffer.anchor_before(range.end.to_point(&display_map));
 3088                mode = SelectMode::Word(start..end);
 3089                auto_scroll = true;
 3090            }
 3091            3 => {
 3092                let position = display_map
 3093                    .clip_point(position, Bias::Left)
 3094                    .to_point(&display_map);
 3095                let line_start = display_map.prev_line_boundary(position).0;
 3096                let next_line_start = buffer.clip_point(
 3097                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3098                    Bias::Left,
 3099                );
 3100                start = buffer.anchor_before(line_start);
 3101                end = buffer.anchor_before(next_line_start);
 3102                mode = SelectMode::Line(start..end);
 3103                auto_scroll = true;
 3104            }
 3105            _ => {
 3106                start = buffer.anchor_before(0);
 3107                end = buffer.anchor_before(buffer.len());
 3108                mode = SelectMode::All;
 3109                auto_scroll = false;
 3110            }
 3111        }
 3112        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3113
 3114        let point_to_delete: Option<usize> = {
 3115            let selected_points: Vec<Selection<Point>> =
 3116                self.selections.disjoint_in_range(start..end, cx);
 3117
 3118            if !add || click_count > 1 {
 3119                None
 3120            } else if !selected_points.is_empty() {
 3121                Some(selected_points[0].id)
 3122            } else {
 3123                let clicked_point_already_selected =
 3124                    self.selections.disjoint.iter().find(|selection| {
 3125                        selection.start.to_point(buffer) == start.to_point(buffer)
 3126                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3127                    });
 3128
 3129                clicked_point_already_selected.map(|selection| selection.id)
 3130            }
 3131        };
 3132
 3133        let selections_count = self.selections.count();
 3134
 3135        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3136            if let Some(point_to_delete) = point_to_delete {
 3137                s.delete(point_to_delete);
 3138
 3139                if selections_count == 1 {
 3140                    s.set_pending_anchor_range(start..end, mode);
 3141                }
 3142            } else {
 3143                if !add {
 3144                    s.clear_disjoint();
 3145                }
 3146
 3147                s.set_pending_anchor_range(start..end, mode);
 3148            }
 3149        });
 3150    }
 3151
 3152    fn begin_columnar_selection(
 3153        &mut self,
 3154        position: DisplayPoint,
 3155        goal_column: u32,
 3156        reset: bool,
 3157        window: &mut Window,
 3158        cx: &mut Context<Self>,
 3159    ) {
 3160        if !self.focus_handle.is_focused(window) {
 3161            self.last_focused_descendant = None;
 3162            window.focus(&self.focus_handle);
 3163        }
 3164
 3165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3166
 3167        if reset {
 3168            let pointer_position = display_map
 3169                .buffer_snapshot
 3170                .anchor_before(position.to_point(&display_map));
 3171
 3172            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3173                s.clear_disjoint();
 3174                s.set_pending_anchor_range(
 3175                    pointer_position..pointer_position,
 3176                    SelectMode::Character,
 3177                );
 3178            });
 3179        }
 3180
 3181        let tail = self.selections.newest::<Point>(cx).tail();
 3182        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3183
 3184        if !reset {
 3185            self.select_columns(
 3186                tail.to_display_point(&display_map),
 3187                position,
 3188                goal_column,
 3189                &display_map,
 3190                window,
 3191                cx,
 3192            );
 3193        }
 3194    }
 3195
 3196    fn update_selection(
 3197        &mut self,
 3198        position: DisplayPoint,
 3199        goal_column: u32,
 3200        scroll_delta: gpui::Point<f32>,
 3201        window: &mut Window,
 3202        cx: &mut Context<Self>,
 3203    ) {
 3204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3205
 3206        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3207            let tail = tail.to_display_point(&display_map);
 3208            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3209        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3210            let buffer = self.buffer.read(cx).snapshot(cx);
 3211            let head;
 3212            let tail;
 3213            let mode = self.selections.pending_mode().unwrap();
 3214            match &mode {
 3215                SelectMode::Character => {
 3216                    head = position.to_point(&display_map);
 3217                    tail = pending.tail().to_point(&buffer);
 3218                }
 3219                SelectMode::Word(original_range) => {
 3220                    let original_display_range = original_range.start.to_display_point(&display_map)
 3221                        ..original_range.end.to_display_point(&display_map);
 3222                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3223                        ..original_display_range.end.to_point(&display_map);
 3224                    if movement::is_inside_word(&display_map, position)
 3225                        || original_display_range.contains(&position)
 3226                    {
 3227                        let word_range = movement::surrounding_word(&display_map, position);
 3228                        if word_range.start < original_display_range.start {
 3229                            head = word_range.start.to_point(&display_map);
 3230                        } else {
 3231                            head = word_range.end.to_point(&display_map);
 3232                        }
 3233                    } else {
 3234                        head = position.to_point(&display_map);
 3235                    }
 3236
 3237                    if head <= original_buffer_range.start {
 3238                        tail = original_buffer_range.end;
 3239                    } else {
 3240                        tail = original_buffer_range.start;
 3241                    }
 3242                }
 3243                SelectMode::Line(original_range) => {
 3244                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3245
 3246                    let position = display_map
 3247                        .clip_point(position, Bias::Left)
 3248                        .to_point(&display_map);
 3249                    let line_start = display_map.prev_line_boundary(position).0;
 3250                    let next_line_start = buffer.clip_point(
 3251                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3252                        Bias::Left,
 3253                    );
 3254
 3255                    if line_start < original_range.start {
 3256                        head = line_start
 3257                    } else {
 3258                        head = next_line_start
 3259                    }
 3260
 3261                    if head <= original_range.start {
 3262                        tail = original_range.end;
 3263                    } else {
 3264                        tail = original_range.start;
 3265                    }
 3266                }
 3267                SelectMode::All => {
 3268                    return;
 3269                }
 3270            };
 3271
 3272            if head < tail {
 3273                pending.start = buffer.anchor_before(head);
 3274                pending.end = buffer.anchor_before(tail);
 3275                pending.reversed = true;
 3276            } else {
 3277                pending.start = buffer.anchor_before(tail);
 3278                pending.end = buffer.anchor_before(head);
 3279                pending.reversed = false;
 3280            }
 3281
 3282            self.change_selections(None, window, cx, |s| {
 3283                s.set_pending(pending, mode);
 3284            });
 3285        } else {
 3286            log::error!("update_selection dispatched with no pending selection");
 3287            return;
 3288        }
 3289
 3290        self.apply_scroll_delta(scroll_delta, window, cx);
 3291        cx.notify();
 3292    }
 3293
 3294    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3295        self.columnar_selection_tail.take();
 3296        if self.selections.pending_anchor().is_some() {
 3297            let selections = self.selections.all::<usize>(cx);
 3298            self.change_selections(None, window, cx, |s| {
 3299                s.select(selections);
 3300                s.clear_pending();
 3301            });
 3302        }
 3303    }
 3304
 3305    fn select_columns(
 3306        &mut self,
 3307        tail: DisplayPoint,
 3308        head: DisplayPoint,
 3309        goal_column: u32,
 3310        display_map: &DisplaySnapshot,
 3311        window: &mut Window,
 3312        cx: &mut Context<Self>,
 3313    ) {
 3314        let start_row = cmp::min(tail.row(), head.row());
 3315        let end_row = cmp::max(tail.row(), head.row());
 3316        let start_column = cmp::min(tail.column(), goal_column);
 3317        let end_column = cmp::max(tail.column(), goal_column);
 3318        let reversed = start_column < tail.column();
 3319
 3320        let selection_ranges = (start_row.0..=end_row.0)
 3321            .map(DisplayRow)
 3322            .filter_map(|row| {
 3323                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3324                    let start = display_map
 3325                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3326                        .to_point(display_map);
 3327                    let end = display_map
 3328                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3329                        .to_point(display_map);
 3330                    if reversed {
 3331                        Some(end..start)
 3332                    } else {
 3333                        Some(start..end)
 3334                    }
 3335                } else {
 3336                    None
 3337                }
 3338            })
 3339            .collect::<Vec<_>>();
 3340
 3341        self.change_selections(None, window, cx, |s| {
 3342            s.select_ranges(selection_ranges);
 3343        });
 3344        cx.notify();
 3345    }
 3346
 3347    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3348        self.selections
 3349            .all_adjusted(cx)
 3350            .iter()
 3351            .any(|selection| !selection.is_empty())
 3352    }
 3353
 3354    pub fn has_pending_nonempty_selection(&self) -> bool {
 3355        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3356            Some(Selection { start, end, .. }) => start != end,
 3357            None => false,
 3358        };
 3359
 3360        pending_nonempty_selection
 3361            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3362    }
 3363
 3364    pub fn has_pending_selection(&self) -> bool {
 3365        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3366    }
 3367
 3368    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3369        self.selection_mark_mode = false;
 3370
 3371        if self.clear_expanded_diff_hunks(cx) {
 3372            cx.notify();
 3373            return;
 3374        }
 3375        if self.dismiss_menus_and_popups(true, window, cx) {
 3376            return;
 3377        }
 3378
 3379        if self.mode.is_full()
 3380            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3381        {
 3382            return;
 3383        }
 3384
 3385        cx.propagate();
 3386    }
 3387
 3388    pub fn dismiss_menus_and_popups(
 3389        &mut self,
 3390        is_user_requested: bool,
 3391        window: &mut Window,
 3392        cx: &mut Context<Self>,
 3393    ) -> bool {
 3394        if self.take_rename(false, window, cx).is_some() {
 3395            return true;
 3396        }
 3397
 3398        if hide_hover(self, cx) {
 3399            return true;
 3400        }
 3401
 3402        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3403            return true;
 3404        }
 3405
 3406        if self.hide_context_menu(window, cx).is_some() {
 3407            return true;
 3408        }
 3409
 3410        if self.mouse_context_menu.take().is_some() {
 3411            return true;
 3412        }
 3413
 3414        if is_user_requested && self.discard_inline_completion(true, cx) {
 3415            return true;
 3416        }
 3417
 3418        if self.snippet_stack.pop().is_some() {
 3419            return true;
 3420        }
 3421
 3422        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3423            self.dismiss_diagnostics(cx);
 3424            return true;
 3425        }
 3426
 3427        false
 3428    }
 3429
 3430    fn linked_editing_ranges_for(
 3431        &self,
 3432        selection: Range<text::Anchor>,
 3433        cx: &App,
 3434    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3435        if self.linked_edit_ranges.is_empty() {
 3436            return None;
 3437        }
 3438        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3439            selection.end.buffer_id.and_then(|end_buffer_id| {
 3440                if selection.start.buffer_id != Some(end_buffer_id) {
 3441                    return None;
 3442                }
 3443                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3444                let snapshot = buffer.read(cx).snapshot();
 3445                self.linked_edit_ranges
 3446                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3447                    .map(|ranges| (ranges, snapshot, buffer))
 3448            })?;
 3449        use text::ToOffset as TO;
 3450        // find offset from the start of current range to current cursor position
 3451        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3452
 3453        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3454        let start_difference = start_offset - start_byte_offset;
 3455        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3456        let end_difference = end_offset - start_byte_offset;
 3457        // Current range has associated linked ranges.
 3458        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3459        for range in linked_ranges.iter() {
 3460            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3461            let end_offset = start_offset + end_difference;
 3462            let start_offset = start_offset + start_difference;
 3463            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3464                continue;
 3465            }
 3466            if self.selections.disjoint_anchor_ranges().any(|s| {
 3467                if s.start.buffer_id != selection.start.buffer_id
 3468                    || s.end.buffer_id != selection.end.buffer_id
 3469                {
 3470                    return false;
 3471                }
 3472                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3473                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3474            }) {
 3475                continue;
 3476            }
 3477            let start = buffer_snapshot.anchor_after(start_offset);
 3478            let end = buffer_snapshot.anchor_after(end_offset);
 3479            linked_edits
 3480                .entry(buffer.clone())
 3481                .or_default()
 3482                .push(start..end);
 3483        }
 3484        Some(linked_edits)
 3485    }
 3486
 3487    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3488        let text: Arc<str> = text.into();
 3489
 3490        if self.read_only(cx) {
 3491            return;
 3492        }
 3493
 3494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3495
 3496        let selections = self.selections.all_adjusted(cx);
 3497        let mut bracket_inserted = false;
 3498        let mut edits = Vec::new();
 3499        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3500        let mut new_selections = Vec::with_capacity(selections.len());
 3501        let mut new_autoclose_regions = Vec::new();
 3502        let snapshot = self.buffer.read(cx).read(cx);
 3503        let mut clear_linked_edit_ranges = false;
 3504
 3505        for (selection, autoclose_region) in
 3506            self.selections_with_autoclose_regions(selections, &snapshot)
 3507        {
 3508            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3509                // Determine if the inserted text matches the opening or closing
 3510                // bracket of any of this language's bracket pairs.
 3511                let mut bracket_pair = None;
 3512                let mut is_bracket_pair_start = false;
 3513                let mut is_bracket_pair_end = false;
 3514                if !text.is_empty() {
 3515                    let mut bracket_pair_matching_end = None;
 3516                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3517                    //  and they are removing the character that triggered IME popup.
 3518                    for (pair, enabled) in scope.brackets() {
 3519                        if !pair.close && !pair.surround {
 3520                            continue;
 3521                        }
 3522
 3523                        if enabled && pair.start.ends_with(text.as_ref()) {
 3524                            let prefix_len = pair.start.len() - text.len();
 3525                            let preceding_text_matches_prefix = prefix_len == 0
 3526                                || (selection.start.column >= (prefix_len as u32)
 3527                                    && snapshot.contains_str_at(
 3528                                        Point::new(
 3529                                            selection.start.row,
 3530                                            selection.start.column - (prefix_len as u32),
 3531                                        ),
 3532                                        &pair.start[..prefix_len],
 3533                                    ));
 3534                            if preceding_text_matches_prefix {
 3535                                bracket_pair = Some(pair.clone());
 3536                                is_bracket_pair_start = true;
 3537                                break;
 3538                            }
 3539                        }
 3540                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3541                        {
 3542                            // take first bracket pair matching end, but don't break in case a later bracket
 3543                            // pair matches start
 3544                            bracket_pair_matching_end = Some(pair.clone());
 3545                        }
 3546                    }
 3547                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3548                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3549                        is_bracket_pair_end = true;
 3550                    }
 3551                }
 3552
 3553                if let Some(bracket_pair) = bracket_pair {
 3554                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3555                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3556                    let auto_surround =
 3557                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3558                    if selection.is_empty() {
 3559                        if is_bracket_pair_start {
 3560                            // If the inserted text is a suffix of an opening bracket and the
 3561                            // selection is preceded by the rest of the opening bracket, then
 3562                            // insert the closing bracket.
 3563                            let following_text_allows_autoclose = snapshot
 3564                                .chars_at(selection.start)
 3565                                .next()
 3566                                .map_or(true, |c| scope.should_autoclose_before(c));
 3567
 3568                            let preceding_text_allows_autoclose = selection.start.column == 0
 3569                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3570                                    true,
 3571                                    |c| {
 3572                                        bracket_pair.start != bracket_pair.end
 3573                                            || !snapshot
 3574                                                .char_classifier_at(selection.start)
 3575                                                .is_word(c)
 3576                                    },
 3577                                );
 3578
 3579                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3580                                && bracket_pair.start.len() == 1
 3581                            {
 3582                                let target = bracket_pair.start.chars().next().unwrap();
 3583                                let current_line_count = snapshot
 3584                                    .reversed_chars_at(selection.start)
 3585                                    .take_while(|&c| c != '\n')
 3586                                    .filter(|&c| c == target)
 3587                                    .count();
 3588                                current_line_count % 2 == 1
 3589                            } else {
 3590                                false
 3591                            };
 3592
 3593                            if autoclose
 3594                                && bracket_pair.close
 3595                                && following_text_allows_autoclose
 3596                                && preceding_text_allows_autoclose
 3597                                && !is_closing_quote
 3598                            {
 3599                                let anchor = snapshot.anchor_before(selection.end);
 3600                                new_selections.push((selection.map(|_| anchor), text.len()));
 3601                                new_autoclose_regions.push((
 3602                                    anchor,
 3603                                    text.len(),
 3604                                    selection.id,
 3605                                    bracket_pair.clone(),
 3606                                ));
 3607                                edits.push((
 3608                                    selection.range(),
 3609                                    format!("{}{}", text, bracket_pair.end).into(),
 3610                                ));
 3611                                bracket_inserted = true;
 3612                                continue;
 3613                            }
 3614                        }
 3615
 3616                        if let Some(region) = autoclose_region {
 3617                            // If the selection is followed by an auto-inserted closing bracket,
 3618                            // then don't insert that closing bracket again; just move the selection
 3619                            // past the closing bracket.
 3620                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3621                                && text.as_ref() == region.pair.end.as_str();
 3622                            if should_skip {
 3623                                let anchor = snapshot.anchor_after(selection.end);
 3624                                new_selections
 3625                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3626                                continue;
 3627                            }
 3628                        }
 3629
 3630                        let always_treat_brackets_as_autoclosed = snapshot
 3631                            .language_settings_at(selection.start, cx)
 3632                            .always_treat_brackets_as_autoclosed;
 3633                        if always_treat_brackets_as_autoclosed
 3634                            && is_bracket_pair_end
 3635                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3636                        {
 3637                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3638                            // and the inserted text is a closing bracket and the selection is followed
 3639                            // by the closing bracket then move the selection past the closing bracket.
 3640                            let anchor = snapshot.anchor_after(selection.end);
 3641                            new_selections.push((selection.map(|_| anchor), text.len()));
 3642                            continue;
 3643                        }
 3644                    }
 3645                    // If an opening bracket is 1 character long and is typed while
 3646                    // text is selected, then surround that text with the bracket pair.
 3647                    else if auto_surround
 3648                        && bracket_pair.surround
 3649                        && is_bracket_pair_start
 3650                        && bracket_pair.start.chars().count() == 1
 3651                    {
 3652                        edits.push((selection.start..selection.start, text.clone()));
 3653                        edits.push((
 3654                            selection.end..selection.end,
 3655                            bracket_pair.end.as_str().into(),
 3656                        ));
 3657                        bracket_inserted = true;
 3658                        new_selections.push((
 3659                            Selection {
 3660                                id: selection.id,
 3661                                start: snapshot.anchor_after(selection.start),
 3662                                end: snapshot.anchor_before(selection.end),
 3663                                reversed: selection.reversed,
 3664                                goal: selection.goal,
 3665                            },
 3666                            0,
 3667                        ));
 3668                        continue;
 3669                    }
 3670                }
 3671            }
 3672
 3673            if self.auto_replace_emoji_shortcode
 3674                && selection.is_empty()
 3675                && text.as_ref().ends_with(':')
 3676            {
 3677                if let Some(possible_emoji_short_code) =
 3678                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3679                {
 3680                    if !possible_emoji_short_code.is_empty() {
 3681                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3682                            let emoji_shortcode_start = Point::new(
 3683                                selection.start.row,
 3684                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3685                            );
 3686
 3687                            // Remove shortcode from buffer
 3688                            edits.push((
 3689                                emoji_shortcode_start..selection.start,
 3690                                "".to_string().into(),
 3691                            ));
 3692                            new_selections.push((
 3693                                Selection {
 3694                                    id: selection.id,
 3695                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3696                                    end: snapshot.anchor_before(selection.start),
 3697                                    reversed: selection.reversed,
 3698                                    goal: selection.goal,
 3699                                },
 3700                                0,
 3701                            ));
 3702
 3703                            // Insert emoji
 3704                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3705                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3706                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3707
 3708                            continue;
 3709                        }
 3710                    }
 3711                }
 3712            }
 3713
 3714            // If not handling any auto-close operation, then just replace the selected
 3715            // text with the given input and move the selection to the end of the
 3716            // newly inserted text.
 3717            let anchor = snapshot.anchor_after(selection.end);
 3718            if !self.linked_edit_ranges.is_empty() {
 3719                let start_anchor = snapshot.anchor_before(selection.start);
 3720
 3721                let is_word_char = text.chars().next().map_or(true, |char| {
 3722                    let classifier = snapshot
 3723                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3724                        .ignore_punctuation(true);
 3725                    classifier.is_word(char)
 3726                });
 3727
 3728                if is_word_char {
 3729                    if let Some(ranges) = self
 3730                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3731                    {
 3732                        for (buffer, edits) in ranges {
 3733                            linked_edits
 3734                                .entry(buffer.clone())
 3735                                .or_default()
 3736                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3737                        }
 3738                    }
 3739                } else {
 3740                    clear_linked_edit_ranges = true;
 3741                }
 3742            }
 3743
 3744            new_selections.push((selection.map(|_| anchor), 0));
 3745            edits.push((selection.start..selection.end, text.clone()));
 3746        }
 3747
 3748        drop(snapshot);
 3749
 3750        self.transact(window, cx, |this, window, cx| {
 3751            if clear_linked_edit_ranges {
 3752                this.linked_edit_ranges.clear();
 3753            }
 3754            let initial_buffer_versions =
 3755                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3756
 3757            this.buffer.update(cx, |buffer, cx| {
 3758                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3759            });
 3760            for (buffer, edits) in linked_edits {
 3761                buffer.update(cx, |buffer, cx| {
 3762                    let snapshot = buffer.snapshot();
 3763                    let edits = edits
 3764                        .into_iter()
 3765                        .map(|(range, text)| {
 3766                            use text::ToPoint as TP;
 3767                            let end_point = TP::to_point(&range.end, &snapshot);
 3768                            let start_point = TP::to_point(&range.start, &snapshot);
 3769                            (start_point..end_point, text)
 3770                        })
 3771                        .sorted_by_key(|(range, _)| range.start);
 3772                    buffer.edit(edits, None, cx);
 3773                })
 3774            }
 3775            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3776            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3777            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3778            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3779                .zip(new_selection_deltas)
 3780                .map(|(selection, delta)| Selection {
 3781                    id: selection.id,
 3782                    start: selection.start + delta,
 3783                    end: selection.end + delta,
 3784                    reversed: selection.reversed,
 3785                    goal: SelectionGoal::None,
 3786                })
 3787                .collect::<Vec<_>>();
 3788
 3789            let mut i = 0;
 3790            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3791                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3792                let start = map.buffer_snapshot.anchor_before(position);
 3793                let end = map.buffer_snapshot.anchor_after(position);
 3794                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3795                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3796                        Ordering::Less => i += 1,
 3797                        Ordering::Greater => break,
 3798                        Ordering::Equal => {
 3799                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3800                                Ordering::Less => i += 1,
 3801                                Ordering::Equal => break,
 3802                                Ordering::Greater => break,
 3803                            }
 3804                        }
 3805                    }
 3806                }
 3807                this.autoclose_regions.insert(
 3808                    i,
 3809                    AutocloseRegion {
 3810                        selection_id,
 3811                        range: start..end,
 3812                        pair,
 3813                    },
 3814                );
 3815            }
 3816
 3817            let had_active_inline_completion = this.has_active_inline_completion();
 3818            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3819                s.select(new_selections)
 3820            });
 3821
 3822            if !bracket_inserted {
 3823                if let Some(on_type_format_task) =
 3824                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3825                {
 3826                    on_type_format_task.detach_and_log_err(cx);
 3827                }
 3828            }
 3829
 3830            let editor_settings = EditorSettings::get_global(cx);
 3831            if bracket_inserted
 3832                && (editor_settings.auto_signature_help
 3833                    || editor_settings.show_signature_help_after_edits)
 3834            {
 3835                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3836            }
 3837
 3838            let trigger_in_words =
 3839                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3840            if this.hard_wrap.is_some() {
 3841                let latest: Range<Point> = this.selections.newest(cx).range();
 3842                if latest.is_empty()
 3843                    && this
 3844                        .buffer()
 3845                        .read(cx)
 3846                        .snapshot(cx)
 3847                        .line_len(MultiBufferRow(latest.start.row))
 3848                        == latest.start.column
 3849                {
 3850                    this.rewrap_impl(
 3851                        RewrapOptions {
 3852                            override_language_settings: true,
 3853                            preserve_existing_whitespace: true,
 3854                        },
 3855                        cx,
 3856                    )
 3857                }
 3858            }
 3859            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3860            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3861            this.refresh_inline_completion(true, false, window, cx);
 3862            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3863        });
 3864    }
 3865
 3866    fn find_possible_emoji_shortcode_at_position(
 3867        snapshot: &MultiBufferSnapshot,
 3868        position: Point,
 3869    ) -> Option<String> {
 3870        let mut chars = Vec::new();
 3871        let mut found_colon = false;
 3872        for char in snapshot.reversed_chars_at(position).take(100) {
 3873            // Found a possible emoji shortcode in the middle of the buffer
 3874            if found_colon {
 3875                if char.is_whitespace() {
 3876                    chars.reverse();
 3877                    return Some(chars.iter().collect());
 3878                }
 3879                // If the previous character is not a whitespace, we are in the middle of a word
 3880                // and we only want to complete the shortcode if the word is made up of other emojis
 3881                let mut containing_word = String::new();
 3882                for ch in snapshot
 3883                    .reversed_chars_at(position)
 3884                    .skip(chars.len() + 1)
 3885                    .take(100)
 3886                {
 3887                    if ch.is_whitespace() {
 3888                        break;
 3889                    }
 3890                    containing_word.push(ch);
 3891                }
 3892                let containing_word = containing_word.chars().rev().collect::<String>();
 3893                if util::word_consists_of_emojis(containing_word.as_str()) {
 3894                    chars.reverse();
 3895                    return Some(chars.iter().collect());
 3896                }
 3897            }
 3898
 3899            if char.is_whitespace() || !char.is_ascii() {
 3900                return None;
 3901            }
 3902            if char == ':' {
 3903                found_colon = true;
 3904            } else {
 3905                chars.push(char);
 3906            }
 3907        }
 3908        // Found a possible emoji shortcode at the beginning of the buffer
 3909        chars.reverse();
 3910        Some(chars.iter().collect())
 3911    }
 3912
 3913    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3915        self.transact(window, cx, |this, window, cx| {
 3916            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3917                let selections = this.selections.all::<usize>(cx);
 3918                let multi_buffer = this.buffer.read(cx);
 3919                let buffer = multi_buffer.snapshot(cx);
 3920                selections
 3921                    .iter()
 3922                    .map(|selection| {
 3923                        let start_point = selection.start.to_point(&buffer);
 3924                        let mut indent =
 3925                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3926                        indent.len = cmp::min(indent.len, start_point.column);
 3927                        let start = selection.start;
 3928                        let end = selection.end;
 3929                        let selection_is_empty = start == end;
 3930                        let language_scope = buffer.language_scope_at(start);
 3931                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3932                            &language_scope
 3933                        {
 3934                            let insert_extra_newline =
 3935                                insert_extra_newline_brackets(&buffer, start..end, language)
 3936                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3937
 3938                            // Comment extension on newline is allowed only for cursor selections
 3939                            let comment_delimiter = maybe!({
 3940                                if !selection_is_empty {
 3941                                    return None;
 3942                                }
 3943
 3944                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3945                                    return None;
 3946                                }
 3947
 3948                                let delimiters = language.line_comment_prefixes();
 3949                                let max_len_of_delimiter =
 3950                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3951                                let (snapshot, range) =
 3952                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3953
 3954                                let mut index_of_first_non_whitespace = 0;
 3955                                let comment_candidate = snapshot
 3956                                    .chars_for_range(range)
 3957                                    .skip_while(|c| {
 3958                                        let should_skip = c.is_whitespace();
 3959                                        if should_skip {
 3960                                            index_of_first_non_whitespace += 1;
 3961                                        }
 3962                                        should_skip
 3963                                    })
 3964                                    .take(max_len_of_delimiter)
 3965                                    .collect::<String>();
 3966                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3967                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3968                                })?;
 3969                                let cursor_is_placed_after_comment_marker =
 3970                                    index_of_first_non_whitespace + comment_prefix.len()
 3971                                        <= start_point.column as usize;
 3972                                if cursor_is_placed_after_comment_marker {
 3973                                    Some(comment_prefix.clone())
 3974                                } else {
 3975                                    None
 3976                                }
 3977                            });
 3978                            (comment_delimiter, insert_extra_newline)
 3979                        } else {
 3980                            (None, false)
 3981                        };
 3982
 3983                        let capacity_for_delimiter = comment_delimiter
 3984                            .as_deref()
 3985                            .map(str::len)
 3986                            .unwrap_or_default();
 3987                        let mut new_text =
 3988                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3989                        new_text.push('\n');
 3990                        new_text.extend(indent.chars());
 3991                        if let Some(delimiter) = &comment_delimiter {
 3992                            new_text.push_str(delimiter);
 3993                        }
 3994                        if insert_extra_newline {
 3995                            new_text = new_text.repeat(2);
 3996                        }
 3997
 3998                        let anchor = buffer.anchor_after(end);
 3999                        let new_selection = selection.map(|_| anchor);
 4000                        (
 4001                            (start..end, new_text),
 4002                            (insert_extra_newline, new_selection),
 4003                        )
 4004                    })
 4005                    .unzip()
 4006            };
 4007
 4008            this.edit_with_autoindent(edits, cx);
 4009            let buffer = this.buffer.read(cx).snapshot(cx);
 4010            let new_selections = selection_fixup_info
 4011                .into_iter()
 4012                .map(|(extra_newline_inserted, new_selection)| {
 4013                    let mut cursor = new_selection.end.to_point(&buffer);
 4014                    if extra_newline_inserted {
 4015                        cursor.row -= 1;
 4016                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4017                    }
 4018                    new_selection.map(|_| cursor)
 4019                })
 4020                .collect();
 4021
 4022            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4023                s.select(new_selections)
 4024            });
 4025            this.refresh_inline_completion(true, false, window, cx);
 4026        });
 4027    }
 4028
 4029    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4030        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4031
 4032        let buffer = self.buffer.read(cx);
 4033        let snapshot = buffer.snapshot(cx);
 4034
 4035        let mut edits = Vec::new();
 4036        let mut rows = Vec::new();
 4037
 4038        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4039            let cursor = selection.head();
 4040            let row = cursor.row;
 4041
 4042            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4043
 4044            let newline = "\n".to_string();
 4045            edits.push((start_of_line..start_of_line, newline));
 4046
 4047            rows.push(row + rows_inserted as u32);
 4048        }
 4049
 4050        self.transact(window, cx, |editor, window, cx| {
 4051            editor.edit(edits, cx);
 4052
 4053            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4054                let mut index = 0;
 4055                s.move_cursors_with(|map, _, _| {
 4056                    let row = rows[index];
 4057                    index += 1;
 4058
 4059                    let point = Point::new(row, 0);
 4060                    let boundary = map.next_line_boundary(point).1;
 4061                    let clipped = map.clip_point(boundary, Bias::Left);
 4062
 4063                    (clipped, SelectionGoal::None)
 4064                });
 4065            });
 4066
 4067            let mut indent_edits = Vec::new();
 4068            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4069            for row in rows {
 4070                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4071                for (row, indent) in indents {
 4072                    if indent.len == 0 {
 4073                        continue;
 4074                    }
 4075
 4076                    let text = match indent.kind {
 4077                        IndentKind::Space => " ".repeat(indent.len as usize),
 4078                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4079                    };
 4080                    let point = Point::new(row.0, 0);
 4081                    indent_edits.push((point..point, text));
 4082                }
 4083            }
 4084            editor.edit(indent_edits, cx);
 4085        });
 4086    }
 4087
 4088    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4089        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4090
 4091        let buffer = self.buffer.read(cx);
 4092        let snapshot = buffer.snapshot(cx);
 4093
 4094        let mut edits = Vec::new();
 4095        let mut rows = Vec::new();
 4096        let mut rows_inserted = 0;
 4097
 4098        for selection in self.selections.all_adjusted(cx) {
 4099            let cursor = selection.head();
 4100            let row = cursor.row;
 4101
 4102            let point = Point::new(row + 1, 0);
 4103            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4104
 4105            let newline = "\n".to_string();
 4106            edits.push((start_of_line..start_of_line, newline));
 4107
 4108            rows_inserted += 1;
 4109            rows.push(row + rows_inserted);
 4110        }
 4111
 4112        self.transact(window, cx, |editor, window, cx| {
 4113            editor.edit(edits, cx);
 4114
 4115            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4116                let mut index = 0;
 4117                s.move_cursors_with(|map, _, _| {
 4118                    let row = rows[index];
 4119                    index += 1;
 4120
 4121                    let point = Point::new(row, 0);
 4122                    let boundary = map.next_line_boundary(point).1;
 4123                    let clipped = map.clip_point(boundary, Bias::Left);
 4124
 4125                    (clipped, SelectionGoal::None)
 4126                });
 4127            });
 4128
 4129            let mut indent_edits = Vec::new();
 4130            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4131            for row in rows {
 4132                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4133                for (row, indent) in indents {
 4134                    if indent.len == 0 {
 4135                        continue;
 4136                    }
 4137
 4138                    let text = match indent.kind {
 4139                        IndentKind::Space => " ".repeat(indent.len as usize),
 4140                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4141                    };
 4142                    let point = Point::new(row.0, 0);
 4143                    indent_edits.push((point..point, text));
 4144                }
 4145            }
 4146            editor.edit(indent_edits, cx);
 4147        });
 4148    }
 4149
 4150    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4151        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4152            original_indent_columns: Vec::new(),
 4153        });
 4154        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4155    }
 4156
 4157    fn insert_with_autoindent_mode(
 4158        &mut self,
 4159        text: &str,
 4160        autoindent_mode: Option<AutoindentMode>,
 4161        window: &mut Window,
 4162        cx: &mut Context<Self>,
 4163    ) {
 4164        if self.read_only(cx) {
 4165            return;
 4166        }
 4167
 4168        let text: Arc<str> = text.into();
 4169        self.transact(window, cx, |this, window, cx| {
 4170            let old_selections = this.selections.all_adjusted(cx);
 4171            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4172                let anchors = {
 4173                    let snapshot = buffer.read(cx);
 4174                    old_selections
 4175                        .iter()
 4176                        .map(|s| {
 4177                            let anchor = snapshot.anchor_after(s.head());
 4178                            s.map(|_| anchor)
 4179                        })
 4180                        .collect::<Vec<_>>()
 4181                };
 4182                buffer.edit(
 4183                    old_selections
 4184                        .iter()
 4185                        .map(|s| (s.start..s.end, text.clone())),
 4186                    autoindent_mode,
 4187                    cx,
 4188                );
 4189                anchors
 4190            });
 4191
 4192            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4193                s.select_anchors(selection_anchors);
 4194            });
 4195
 4196            cx.notify();
 4197        });
 4198    }
 4199
 4200    fn trigger_completion_on_input(
 4201        &mut self,
 4202        text: &str,
 4203        trigger_in_words: bool,
 4204        window: &mut Window,
 4205        cx: &mut Context<Self>,
 4206    ) {
 4207        let ignore_completion_provider = self
 4208            .context_menu
 4209            .borrow()
 4210            .as_ref()
 4211            .map(|menu| match menu {
 4212                CodeContextMenu::Completions(completions_menu) => {
 4213                    completions_menu.ignore_completion_provider
 4214                }
 4215                CodeContextMenu::CodeActions(_) => false,
 4216            })
 4217            .unwrap_or(false);
 4218
 4219        if ignore_completion_provider {
 4220            self.show_word_completions(&ShowWordCompletions, window, cx);
 4221        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4222            self.show_completions(
 4223                &ShowCompletions {
 4224                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4225                },
 4226                window,
 4227                cx,
 4228            );
 4229        } else {
 4230            self.hide_context_menu(window, cx);
 4231        }
 4232    }
 4233
 4234    fn is_completion_trigger(
 4235        &self,
 4236        text: &str,
 4237        trigger_in_words: bool,
 4238        cx: &mut Context<Self>,
 4239    ) -> bool {
 4240        let position = self.selections.newest_anchor().head();
 4241        let multibuffer = self.buffer.read(cx);
 4242        let Some(buffer) = position
 4243            .buffer_id
 4244            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4245        else {
 4246            return false;
 4247        };
 4248
 4249        if let Some(completion_provider) = &self.completion_provider {
 4250            completion_provider.is_completion_trigger(
 4251                &buffer,
 4252                position.text_anchor,
 4253                text,
 4254                trigger_in_words,
 4255                cx,
 4256            )
 4257        } else {
 4258            false
 4259        }
 4260    }
 4261
 4262    /// If any empty selections is touching the start of its innermost containing autoclose
 4263    /// region, expand it to select the brackets.
 4264    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4265        let selections = self.selections.all::<usize>(cx);
 4266        let buffer = self.buffer.read(cx).read(cx);
 4267        let new_selections = self
 4268            .selections_with_autoclose_regions(selections, &buffer)
 4269            .map(|(mut selection, region)| {
 4270                if !selection.is_empty() {
 4271                    return selection;
 4272                }
 4273
 4274                if let Some(region) = region {
 4275                    let mut range = region.range.to_offset(&buffer);
 4276                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4277                        range.start -= region.pair.start.len();
 4278                        if buffer.contains_str_at(range.start, &region.pair.start)
 4279                            && buffer.contains_str_at(range.end, &region.pair.end)
 4280                        {
 4281                            range.end += region.pair.end.len();
 4282                            selection.start = range.start;
 4283                            selection.end = range.end;
 4284
 4285                            return selection;
 4286                        }
 4287                    }
 4288                }
 4289
 4290                let always_treat_brackets_as_autoclosed = buffer
 4291                    .language_settings_at(selection.start, cx)
 4292                    .always_treat_brackets_as_autoclosed;
 4293
 4294                if !always_treat_brackets_as_autoclosed {
 4295                    return selection;
 4296                }
 4297
 4298                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4299                    for (pair, enabled) in scope.brackets() {
 4300                        if !enabled || !pair.close {
 4301                            continue;
 4302                        }
 4303
 4304                        if buffer.contains_str_at(selection.start, &pair.end) {
 4305                            let pair_start_len = pair.start.len();
 4306                            if buffer.contains_str_at(
 4307                                selection.start.saturating_sub(pair_start_len),
 4308                                &pair.start,
 4309                            ) {
 4310                                selection.start -= pair_start_len;
 4311                                selection.end += pair.end.len();
 4312
 4313                                return selection;
 4314                            }
 4315                        }
 4316                    }
 4317                }
 4318
 4319                selection
 4320            })
 4321            .collect();
 4322
 4323        drop(buffer);
 4324        self.change_selections(None, window, cx, |selections| {
 4325            selections.select(new_selections)
 4326        });
 4327    }
 4328
 4329    /// Iterate the given selections, and for each one, find the smallest surrounding
 4330    /// autoclose region. This uses the ordering of the selections and the autoclose
 4331    /// regions to avoid repeated comparisons.
 4332    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4333        &'a self,
 4334        selections: impl IntoIterator<Item = Selection<D>>,
 4335        buffer: &'a MultiBufferSnapshot,
 4336    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4337        let mut i = 0;
 4338        let mut regions = self.autoclose_regions.as_slice();
 4339        selections.into_iter().map(move |selection| {
 4340            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4341
 4342            let mut enclosing = None;
 4343            while let Some(pair_state) = regions.get(i) {
 4344                if pair_state.range.end.to_offset(buffer) < range.start {
 4345                    regions = &regions[i + 1..];
 4346                    i = 0;
 4347                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4348                    break;
 4349                } else {
 4350                    if pair_state.selection_id == selection.id {
 4351                        enclosing = Some(pair_state);
 4352                    }
 4353                    i += 1;
 4354                }
 4355            }
 4356
 4357            (selection, enclosing)
 4358        })
 4359    }
 4360
 4361    /// Remove any autoclose regions that no longer contain their selection.
 4362    fn invalidate_autoclose_regions(
 4363        &mut self,
 4364        mut selections: &[Selection<Anchor>],
 4365        buffer: &MultiBufferSnapshot,
 4366    ) {
 4367        self.autoclose_regions.retain(|state| {
 4368            let mut i = 0;
 4369            while let Some(selection) = selections.get(i) {
 4370                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4371                    selections = &selections[1..];
 4372                    continue;
 4373                }
 4374                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4375                    break;
 4376                }
 4377                if selection.id == state.selection_id {
 4378                    return true;
 4379                } else {
 4380                    i += 1;
 4381                }
 4382            }
 4383            false
 4384        });
 4385    }
 4386
 4387    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4388        let offset = position.to_offset(buffer);
 4389        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4390        if offset > word_range.start && kind == Some(CharKind::Word) {
 4391            Some(
 4392                buffer
 4393                    .text_for_range(word_range.start..offset)
 4394                    .collect::<String>(),
 4395            )
 4396        } else {
 4397            None
 4398        }
 4399    }
 4400
 4401    pub fn toggle_inline_values(
 4402        &mut self,
 4403        _: &ToggleInlineValues,
 4404        _: &mut Window,
 4405        cx: &mut Context<Self>,
 4406    ) {
 4407        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4408
 4409        self.refresh_inline_values(cx);
 4410    }
 4411
 4412    pub fn toggle_inlay_hints(
 4413        &mut self,
 4414        _: &ToggleInlayHints,
 4415        _: &mut Window,
 4416        cx: &mut Context<Self>,
 4417    ) {
 4418        self.refresh_inlay_hints(
 4419            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4420            cx,
 4421        );
 4422    }
 4423
 4424    pub fn inlay_hints_enabled(&self) -> bool {
 4425        self.inlay_hint_cache.enabled
 4426    }
 4427
 4428    pub fn inline_values_enabled(&self) -> bool {
 4429        self.inline_value_cache.enabled
 4430    }
 4431
 4432    #[cfg(any(test, feature = "test-support"))]
 4433    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4434        self.display_map
 4435            .read(cx)
 4436            .current_inlays()
 4437            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4438            .cloned()
 4439            .collect()
 4440    }
 4441
 4442    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4443        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4444            return;
 4445        }
 4446
 4447        let reason_description = reason.description();
 4448        let ignore_debounce = matches!(
 4449            reason,
 4450            InlayHintRefreshReason::SettingsChange(_)
 4451                | InlayHintRefreshReason::Toggle(_)
 4452                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4453                | InlayHintRefreshReason::ModifiersChanged(_)
 4454        );
 4455        let (invalidate_cache, required_languages) = match reason {
 4456            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4457                match self.inlay_hint_cache.modifiers_override(enabled) {
 4458                    Some(enabled) => {
 4459                        if enabled {
 4460                            (InvalidationStrategy::RefreshRequested, None)
 4461                        } else {
 4462                            self.splice_inlays(
 4463                                &self
 4464                                    .visible_inlay_hints(cx)
 4465                                    .iter()
 4466                                    .map(|inlay| inlay.id)
 4467                                    .collect::<Vec<InlayId>>(),
 4468                                Vec::new(),
 4469                                cx,
 4470                            );
 4471                            return;
 4472                        }
 4473                    }
 4474                    None => return,
 4475                }
 4476            }
 4477            InlayHintRefreshReason::Toggle(enabled) => {
 4478                if self.inlay_hint_cache.toggle(enabled) {
 4479                    if enabled {
 4480                        (InvalidationStrategy::RefreshRequested, None)
 4481                    } else {
 4482                        self.splice_inlays(
 4483                            &self
 4484                                .visible_inlay_hints(cx)
 4485                                .iter()
 4486                                .map(|inlay| inlay.id)
 4487                                .collect::<Vec<InlayId>>(),
 4488                            Vec::new(),
 4489                            cx,
 4490                        );
 4491                        return;
 4492                    }
 4493                } else {
 4494                    return;
 4495                }
 4496            }
 4497            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4498                match self.inlay_hint_cache.update_settings(
 4499                    &self.buffer,
 4500                    new_settings,
 4501                    self.visible_inlay_hints(cx),
 4502                    cx,
 4503                ) {
 4504                    ControlFlow::Break(Some(InlaySplice {
 4505                        to_remove,
 4506                        to_insert,
 4507                    })) => {
 4508                        self.splice_inlays(&to_remove, to_insert, cx);
 4509                        return;
 4510                    }
 4511                    ControlFlow::Break(None) => return,
 4512                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4513                }
 4514            }
 4515            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4516                if let Some(InlaySplice {
 4517                    to_remove,
 4518                    to_insert,
 4519                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4520                {
 4521                    self.splice_inlays(&to_remove, to_insert, cx);
 4522                }
 4523                self.display_map.update(cx, |display_map, _| {
 4524                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4525                });
 4526                return;
 4527            }
 4528            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4529            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4530                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4531            }
 4532            InlayHintRefreshReason::RefreshRequested => {
 4533                (InvalidationStrategy::RefreshRequested, None)
 4534            }
 4535        };
 4536
 4537        if let Some(InlaySplice {
 4538            to_remove,
 4539            to_insert,
 4540        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4541            reason_description,
 4542            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4543            invalidate_cache,
 4544            ignore_debounce,
 4545            cx,
 4546        ) {
 4547            self.splice_inlays(&to_remove, to_insert, cx);
 4548        }
 4549    }
 4550
 4551    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4552        self.display_map
 4553            .read(cx)
 4554            .current_inlays()
 4555            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4556            .cloned()
 4557            .collect()
 4558    }
 4559
 4560    pub fn excerpts_for_inlay_hints_query(
 4561        &self,
 4562        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4563        cx: &mut Context<Editor>,
 4564    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4565        let Some(project) = self.project.as_ref() else {
 4566            return HashMap::default();
 4567        };
 4568        let project = project.read(cx);
 4569        let multi_buffer = self.buffer().read(cx);
 4570        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4571        let multi_buffer_visible_start = self
 4572            .scroll_manager
 4573            .anchor()
 4574            .anchor
 4575            .to_point(&multi_buffer_snapshot);
 4576        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4577            multi_buffer_visible_start
 4578                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4579            Bias::Left,
 4580        );
 4581        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4582        multi_buffer_snapshot
 4583            .range_to_buffer_ranges(multi_buffer_visible_range)
 4584            .into_iter()
 4585            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4586            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4587                let buffer_file = project::File::from_dyn(buffer.file())?;
 4588                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4589                let worktree_entry = buffer_worktree
 4590                    .read(cx)
 4591                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4592                if worktree_entry.is_ignored {
 4593                    return None;
 4594                }
 4595
 4596                let language = buffer.language()?;
 4597                if let Some(restrict_to_languages) = restrict_to_languages {
 4598                    if !restrict_to_languages.contains(language) {
 4599                        return None;
 4600                    }
 4601                }
 4602                Some((
 4603                    excerpt_id,
 4604                    (
 4605                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4606                        buffer.version().clone(),
 4607                        excerpt_visible_range,
 4608                    ),
 4609                ))
 4610            })
 4611            .collect()
 4612    }
 4613
 4614    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4615        TextLayoutDetails {
 4616            text_system: window.text_system().clone(),
 4617            editor_style: self.style.clone().unwrap(),
 4618            rem_size: window.rem_size(),
 4619            scroll_anchor: self.scroll_manager.anchor(),
 4620            visible_rows: self.visible_line_count(),
 4621            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4622        }
 4623    }
 4624
 4625    pub fn splice_inlays(
 4626        &self,
 4627        to_remove: &[InlayId],
 4628        to_insert: Vec<Inlay>,
 4629        cx: &mut Context<Self>,
 4630    ) {
 4631        self.display_map.update(cx, |display_map, cx| {
 4632            display_map.splice_inlays(to_remove, to_insert, cx)
 4633        });
 4634        cx.notify();
 4635    }
 4636
 4637    fn trigger_on_type_formatting(
 4638        &self,
 4639        input: String,
 4640        window: &mut Window,
 4641        cx: &mut Context<Self>,
 4642    ) -> Option<Task<Result<()>>> {
 4643        if input.len() != 1 {
 4644            return None;
 4645        }
 4646
 4647        let project = self.project.as_ref()?;
 4648        let position = self.selections.newest_anchor().head();
 4649        let (buffer, buffer_position) = self
 4650            .buffer
 4651            .read(cx)
 4652            .text_anchor_for_position(position, cx)?;
 4653
 4654        let settings = language_settings::language_settings(
 4655            buffer
 4656                .read(cx)
 4657                .language_at(buffer_position)
 4658                .map(|l| l.name()),
 4659            buffer.read(cx).file(),
 4660            cx,
 4661        );
 4662        if !settings.use_on_type_format {
 4663            return None;
 4664        }
 4665
 4666        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4667        // hence we do LSP request & edit on host side only — add formats to host's history.
 4668        let push_to_lsp_host_history = true;
 4669        // If this is not the host, append its history with new edits.
 4670        let push_to_client_history = project.read(cx).is_via_collab();
 4671
 4672        let on_type_formatting = project.update(cx, |project, cx| {
 4673            project.on_type_format(
 4674                buffer.clone(),
 4675                buffer_position,
 4676                input,
 4677                push_to_lsp_host_history,
 4678                cx,
 4679            )
 4680        });
 4681        Some(cx.spawn_in(window, async move |editor, cx| {
 4682            if let Some(transaction) = on_type_formatting.await? {
 4683                if push_to_client_history {
 4684                    buffer
 4685                        .update(cx, |buffer, _| {
 4686                            buffer.push_transaction(transaction, Instant::now());
 4687                            buffer.finalize_last_transaction();
 4688                        })
 4689                        .ok();
 4690                }
 4691                editor.update(cx, |editor, cx| {
 4692                    editor.refresh_document_highlights(cx);
 4693                })?;
 4694            }
 4695            Ok(())
 4696        }))
 4697    }
 4698
 4699    pub fn show_word_completions(
 4700        &mut self,
 4701        _: &ShowWordCompletions,
 4702        window: &mut Window,
 4703        cx: &mut Context<Self>,
 4704    ) {
 4705        self.open_completions_menu(true, None, window, cx);
 4706    }
 4707
 4708    pub fn show_completions(
 4709        &mut self,
 4710        options: &ShowCompletions,
 4711        window: &mut Window,
 4712        cx: &mut Context<Self>,
 4713    ) {
 4714        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4715    }
 4716
 4717    fn open_completions_menu(
 4718        &mut self,
 4719        ignore_completion_provider: bool,
 4720        trigger: Option<&str>,
 4721        window: &mut Window,
 4722        cx: &mut Context<Self>,
 4723    ) {
 4724        if self.pending_rename.is_some() {
 4725            return;
 4726        }
 4727        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4728            return;
 4729        }
 4730
 4731        let position = self.selections.newest_anchor().head();
 4732        if position.diff_base_anchor.is_some() {
 4733            return;
 4734        }
 4735        let (buffer, buffer_position) =
 4736            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4737                output
 4738            } else {
 4739                return;
 4740            };
 4741        let buffer_snapshot = buffer.read(cx).snapshot();
 4742        let show_completion_documentation = buffer_snapshot
 4743            .settings_at(buffer_position, cx)
 4744            .show_completion_documentation;
 4745
 4746        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4747
 4748        let trigger_kind = match trigger {
 4749            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4750                CompletionTriggerKind::TRIGGER_CHARACTER
 4751            }
 4752            _ => CompletionTriggerKind::INVOKED,
 4753        };
 4754        let completion_context = CompletionContext {
 4755            trigger_character: trigger.and_then(|trigger| {
 4756                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4757                    Some(String::from(trigger))
 4758                } else {
 4759                    None
 4760                }
 4761            }),
 4762            trigger_kind,
 4763        };
 4764
 4765        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4766        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4767            let word_to_exclude = buffer_snapshot
 4768                .text_for_range(old_range.clone())
 4769                .collect::<String>();
 4770            (
 4771                buffer_snapshot.anchor_before(old_range.start)
 4772                    ..buffer_snapshot.anchor_after(old_range.end),
 4773                Some(word_to_exclude),
 4774            )
 4775        } else {
 4776            (buffer_position..buffer_position, None)
 4777        };
 4778
 4779        let completion_settings = language_settings(
 4780            buffer_snapshot
 4781                .language_at(buffer_position)
 4782                .map(|language| language.name()),
 4783            buffer_snapshot.file(),
 4784            cx,
 4785        )
 4786        .completions;
 4787
 4788        // The document can be large, so stay in reasonable bounds when searching for words,
 4789        // otherwise completion pop-up might be slow to appear.
 4790        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4791        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4792        let min_word_search = buffer_snapshot.clip_point(
 4793            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4794            Bias::Left,
 4795        );
 4796        let max_word_search = buffer_snapshot.clip_point(
 4797            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4798            Bias::Right,
 4799        );
 4800        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4801            ..buffer_snapshot.point_to_offset(max_word_search);
 4802
 4803        let provider = self
 4804            .completion_provider
 4805            .as_ref()
 4806            .filter(|_| !ignore_completion_provider);
 4807        let skip_digits = query
 4808            .as_ref()
 4809            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4810
 4811        let (mut words, provided_completions) = match provider {
 4812            Some(provider) => {
 4813                let completions = provider.completions(
 4814                    position.excerpt_id,
 4815                    &buffer,
 4816                    buffer_position,
 4817                    completion_context,
 4818                    window,
 4819                    cx,
 4820                );
 4821
 4822                let words = match completion_settings.words {
 4823                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4824                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4825                        .background_spawn(async move {
 4826                            buffer_snapshot.words_in_range(WordsQuery {
 4827                                fuzzy_contents: None,
 4828                                range: word_search_range,
 4829                                skip_digits,
 4830                            })
 4831                        }),
 4832                };
 4833
 4834                (words, completions)
 4835            }
 4836            None => (
 4837                cx.background_spawn(async move {
 4838                    buffer_snapshot.words_in_range(WordsQuery {
 4839                        fuzzy_contents: None,
 4840                        range: word_search_range,
 4841                        skip_digits,
 4842                    })
 4843                }),
 4844                Task::ready(Ok(None)),
 4845            ),
 4846        };
 4847
 4848        let sort_completions = provider
 4849            .as_ref()
 4850            .map_or(false, |provider| provider.sort_completions());
 4851
 4852        let filter_completions = provider
 4853            .as_ref()
 4854            .map_or(true, |provider| provider.filter_completions());
 4855
 4856        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 4857
 4858        let id = post_inc(&mut self.next_completion_id);
 4859        let task = cx.spawn_in(window, async move |editor, cx| {
 4860            async move {
 4861                editor.update(cx, |this, _| {
 4862                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 4863                })?;
 4864
 4865                let mut completions = Vec::new();
 4866                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 4867                    completions.extend(provided_completions);
 4868                    if completion_settings.words == WordsCompletionMode::Fallback {
 4869                        words = Task::ready(BTreeMap::default());
 4870                    }
 4871                }
 4872
 4873                let mut words = words.await;
 4874                if let Some(word_to_exclude) = &word_to_exclude {
 4875                    words.remove(word_to_exclude);
 4876                }
 4877                for lsp_completion in &completions {
 4878                    words.remove(&lsp_completion.new_text);
 4879                }
 4880                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 4881                    replace_range: old_range.clone(),
 4882                    new_text: word.clone(),
 4883                    label: CodeLabel::plain(word, None),
 4884                    icon_path: None,
 4885                    documentation: None,
 4886                    source: CompletionSource::BufferWord {
 4887                        word_range,
 4888                        resolved: false,
 4889                    },
 4890                    insert_text_mode: Some(InsertTextMode::AS_IS),
 4891                    confirm: None,
 4892                }));
 4893
 4894                let menu = if completions.is_empty() {
 4895                    None
 4896                } else {
 4897                    let mut menu = CompletionsMenu::new(
 4898                        id,
 4899                        sort_completions,
 4900                        show_completion_documentation,
 4901                        ignore_completion_provider,
 4902                        position,
 4903                        buffer.clone(),
 4904                        completions.into(),
 4905                        snippet_sort_order,
 4906                    );
 4907
 4908                    menu.filter(
 4909                        if filter_completions {
 4910                            query.as_deref()
 4911                        } else {
 4912                            None
 4913                        },
 4914                        cx.background_executor().clone(),
 4915                    )
 4916                    .await;
 4917
 4918                    menu.visible().then_some(menu)
 4919                };
 4920
 4921                editor.update_in(cx, |editor, window, cx| {
 4922                    match editor.context_menu.borrow().as_ref() {
 4923                        None => {}
 4924                        Some(CodeContextMenu::Completions(prev_menu)) => {
 4925                            if prev_menu.id > id {
 4926                                return;
 4927                            }
 4928                        }
 4929                        _ => return,
 4930                    }
 4931
 4932                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 4933                        let mut menu = menu.unwrap();
 4934                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 4935
 4936                        *editor.context_menu.borrow_mut() =
 4937                            Some(CodeContextMenu::Completions(menu));
 4938
 4939                        if editor.show_edit_predictions_in_menu() {
 4940                            editor.update_visible_inline_completion(window, cx);
 4941                        } else {
 4942                            editor.discard_inline_completion(false, cx);
 4943                        }
 4944
 4945                        cx.notify();
 4946                    } else if editor.completion_tasks.len() <= 1 {
 4947                        // If there are no more completion tasks and the last menu was
 4948                        // empty, we should hide it.
 4949                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 4950                        // If it was already hidden and we don't show inline
 4951                        // completions in the menu, we should also show the
 4952                        // inline-completion when available.
 4953                        if was_hidden && editor.show_edit_predictions_in_menu() {
 4954                            editor.update_visible_inline_completion(window, cx);
 4955                        }
 4956                    }
 4957                })?;
 4958
 4959                anyhow::Ok(())
 4960            }
 4961            .log_err()
 4962            .await
 4963        });
 4964
 4965        self.completion_tasks.push((id, task));
 4966    }
 4967
 4968    #[cfg(feature = "test-support")]
 4969    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 4970        let menu = self.context_menu.borrow();
 4971        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 4972            let completions = menu.completions.borrow();
 4973            Some(completions.to_vec())
 4974        } else {
 4975            None
 4976        }
 4977    }
 4978
 4979    pub fn confirm_completion(
 4980        &mut self,
 4981        action: &ConfirmCompletion,
 4982        window: &mut Window,
 4983        cx: &mut Context<Self>,
 4984    ) -> Option<Task<Result<()>>> {
 4985        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4986        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 4987    }
 4988
 4989    pub fn confirm_completion_insert(
 4990        &mut self,
 4991        _: &ConfirmCompletionInsert,
 4992        window: &mut Window,
 4993        cx: &mut Context<Self>,
 4994    ) -> Option<Task<Result<()>>> {
 4995        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4996        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 4997    }
 4998
 4999    pub fn confirm_completion_replace(
 5000        &mut self,
 5001        _: &ConfirmCompletionReplace,
 5002        window: &mut Window,
 5003        cx: &mut Context<Self>,
 5004    ) -> Option<Task<Result<()>>> {
 5005        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5006        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5007    }
 5008
 5009    pub fn compose_completion(
 5010        &mut self,
 5011        action: &ComposeCompletion,
 5012        window: &mut Window,
 5013        cx: &mut Context<Self>,
 5014    ) -> Option<Task<Result<()>>> {
 5015        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5016        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5017    }
 5018
 5019    fn do_completion(
 5020        &mut self,
 5021        item_ix: Option<usize>,
 5022        intent: CompletionIntent,
 5023        window: &mut Window,
 5024        cx: &mut Context<Editor>,
 5025    ) -> Option<Task<Result<()>>> {
 5026        use language::ToOffset as _;
 5027
 5028        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5029        else {
 5030            return None;
 5031        };
 5032
 5033        let candidate_id = {
 5034            let entries = completions_menu.entries.borrow();
 5035            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5036            if self.show_edit_predictions_in_menu() {
 5037                self.discard_inline_completion(true, cx);
 5038            }
 5039            mat.candidate_id
 5040        };
 5041
 5042        let buffer_handle = completions_menu.buffer;
 5043        let completion = completions_menu
 5044            .completions
 5045            .borrow()
 5046            .get(candidate_id)?
 5047            .clone();
 5048        cx.stop_propagation();
 5049
 5050        let snapshot = self.buffer.read(cx).snapshot(cx);
 5051        let newest_anchor = self.selections.newest_anchor();
 5052
 5053        let snippet;
 5054        let new_text;
 5055        if completion.is_snippet() {
 5056            let mut snippet_source = completion.new_text.clone();
 5057            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5058                if scope.prefers_label_for_snippet_in_completion() {
 5059                    if let Some(label) = completion.label() {
 5060                        if matches!(
 5061                            completion.kind(),
 5062                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5063                        ) {
 5064                            snippet_source = label;
 5065                        }
 5066                    }
 5067                }
 5068            }
 5069            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5070            new_text = snippet.as_ref().unwrap().text.clone();
 5071        } else {
 5072            snippet = None;
 5073            new_text = completion.new_text.clone();
 5074        };
 5075
 5076        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5077        let buffer = buffer_handle.read(cx);
 5078        let replace_range_multibuffer = {
 5079            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5080            let multibuffer_anchor = snapshot
 5081                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5082                .unwrap()
 5083                ..snapshot
 5084                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5085                    .unwrap();
 5086            multibuffer_anchor.start.to_offset(&snapshot)
 5087                ..multibuffer_anchor.end.to_offset(&snapshot)
 5088        };
 5089        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5090            return None;
 5091        }
 5092
 5093        let old_text = buffer
 5094            .text_for_range(replace_range.clone())
 5095            .collect::<String>();
 5096        let lookbehind = newest_anchor
 5097            .start
 5098            .text_anchor
 5099            .to_offset(buffer)
 5100            .saturating_sub(replace_range.start);
 5101        let lookahead = replace_range
 5102            .end
 5103            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5104        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5105        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5106
 5107        let selections = self.selections.all::<usize>(cx);
 5108        let mut ranges = Vec::new();
 5109        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5110
 5111        for selection in &selections {
 5112            let range = if selection.id == newest_anchor.id {
 5113                replace_range_multibuffer.clone()
 5114            } else {
 5115                let mut range = selection.range();
 5116
 5117                // if prefix is present, don't duplicate it
 5118                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5119                    range.start = range.start.saturating_sub(lookbehind);
 5120
 5121                    // if suffix is also present, mimic the newest cursor and replace it
 5122                    if selection.id != newest_anchor.id
 5123                        && snapshot.contains_str_at(range.end, suffix)
 5124                    {
 5125                        range.end += lookahead;
 5126                    }
 5127                }
 5128                range
 5129            };
 5130
 5131            ranges.push(range.clone());
 5132
 5133            if !self.linked_edit_ranges.is_empty() {
 5134                let start_anchor = snapshot.anchor_before(range.start);
 5135                let end_anchor = snapshot.anchor_after(range.end);
 5136                if let Some(ranges) = self
 5137                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5138                {
 5139                    for (buffer, edits) in ranges {
 5140                        linked_edits
 5141                            .entry(buffer.clone())
 5142                            .or_default()
 5143                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5144                    }
 5145                }
 5146            }
 5147        }
 5148
 5149        cx.emit(EditorEvent::InputHandled {
 5150            utf16_range_to_replace: None,
 5151            text: new_text.clone().into(),
 5152        });
 5153
 5154        self.transact(window, cx, |this, window, cx| {
 5155            if let Some(mut snippet) = snippet {
 5156                snippet.text = new_text.to_string();
 5157                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5158            } else {
 5159                this.buffer.update(cx, |buffer, cx| {
 5160                    let auto_indent = match completion.insert_text_mode {
 5161                        Some(InsertTextMode::AS_IS) => None,
 5162                        _ => this.autoindent_mode.clone(),
 5163                    };
 5164                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5165                    buffer.edit(edits, auto_indent, cx);
 5166                });
 5167            }
 5168            for (buffer, edits) in linked_edits {
 5169                buffer.update(cx, |buffer, cx| {
 5170                    let snapshot = buffer.snapshot();
 5171                    let edits = edits
 5172                        .into_iter()
 5173                        .map(|(range, text)| {
 5174                            use text::ToPoint as TP;
 5175                            let end_point = TP::to_point(&range.end, &snapshot);
 5176                            let start_point = TP::to_point(&range.start, &snapshot);
 5177                            (start_point..end_point, text)
 5178                        })
 5179                        .sorted_by_key(|(range, _)| range.start);
 5180                    buffer.edit(edits, None, cx);
 5181                })
 5182            }
 5183
 5184            this.refresh_inline_completion(true, false, window, cx);
 5185        });
 5186
 5187        let show_new_completions_on_confirm = completion
 5188            .confirm
 5189            .as_ref()
 5190            .map_or(false, |confirm| confirm(intent, window, cx));
 5191        if show_new_completions_on_confirm {
 5192            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5193        }
 5194
 5195        let provider = self.completion_provider.as_ref()?;
 5196        drop(completion);
 5197        let apply_edits = provider.apply_additional_edits_for_completion(
 5198            buffer_handle,
 5199            completions_menu.completions.clone(),
 5200            candidate_id,
 5201            true,
 5202            cx,
 5203        );
 5204
 5205        let editor_settings = EditorSettings::get_global(cx);
 5206        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5207            // After the code completion is finished, users often want to know what signatures are needed.
 5208            // so we should automatically call signature_help
 5209            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5210        }
 5211
 5212        Some(cx.foreground_executor().spawn(async move {
 5213            apply_edits.await?;
 5214            Ok(())
 5215        }))
 5216    }
 5217
 5218    pub fn toggle_code_actions(
 5219        &mut self,
 5220        action: &ToggleCodeActions,
 5221        window: &mut Window,
 5222        cx: &mut Context<Self>,
 5223    ) {
 5224        let quick_launch = action.quick_launch;
 5225        let mut context_menu = self.context_menu.borrow_mut();
 5226        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5227            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5228                // Toggle if we're selecting the same one
 5229                *context_menu = None;
 5230                cx.notify();
 5231                return;
 5232            } else {
 5233                // Otherwise, clear it and start a new one
 5234                *context_menu = None;
 5235                cx.notify();
 5236            }
 5237        }
 5238        drop(context_menu);
 5239        let snapshot = self.snapshot(window, cx);
 5240        let deployed_from_indicator = action.deployed_from_indicator;
 5241        let mut task = self.code_actions_task.take();
 5242        let action = action.clone();
 5243        cx.spawn_in(window, async move |editor, cx| {
 5244            while let Some(prev_task) = task {
 5245                prev_task.await.log_err();
 5246                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5247            }
 5248
 5249            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5250                if editor.focus_handle.is_focused(window) {
 5251                    let multibuffer_point = action
 5252                        .deployed_from_indicator
 5253                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5254                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5255                    let (buffer, buffer_row) = snapshot
 5256                        .buffer_snapshot
 5257                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5258                        .and_then(|(buffer_snapshot, range)| {
 5259                            editor
 5260                                .buffer
 5261                                .read(cx)
 5262                                .buffer(buffer_snapshot.remote_id())
 5263                                .map(|buffer| (buffer, range.start.row))
 5264                        })?;
 5265                    let (_, code_actions) = editor
 5266                        .available_code_actions
 5267                        .clone()
 5268                        .and_then(|(location, code_actions)| {
 5269                            let snapshot = location.buffer.read(cx).snapshot();
 5270                            let point_range = location.range.to_point(&snapshot);
 5271                            let point_range = point_range.start.row..=point_range.end.row;
 5272                            if point_range.contains(&buffer_row) {
 5273                                Some((location, code_actions))
 5274                            } else {
 5275                                None
 5276                            }
 5277                        })
 5278                        .unzip();
 5279                    let buffer_id = buffer.read(cx).remote_id();
 5280                    let tasks = editor
 5281                        .tasks
 5282                        .get(&(buffer_id, buffer_row))
 5283                        .map(|t| Arc::new(t.to_owned()));
 5284                    if tasks.is_none() && code_actions.is_none() {
 5285                        return None;
 5286                    }
 5287
 5288                    editor.completion_tasks.clear();
 5289                    editor.discard_inline_completion(false, cx);
 5290                    let task_context =
 5291                        tasks
 5292                            .as_ref()
 5293                            .zip(editor.project.clone())
 5294                            .map(|(tasks, project)| {
 5295                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5296                            });
 5297
 5298                    Some(cx.spawn_in(window, async move |editor, cx| {
 5299                        let task_context = match task_context {
 5300                            Some(task_context) => task_context.await,
 5301                            None => None,
 5302                        };
 5303                        let resolved_tasks =
 5304                            tasks
 5305                                .zip(task_context.clone())
 5306                                .map(|(tasks, task_context)| ResolvedTasks {
 5307                                    templates: tasks.resolve(&task_context).collect(),
 5308                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5309                                        multibuffer_point.row,
 5310                                        tasks.column,
 5311                                    )),
 5312                                });
 5313                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5314                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5315                                maybe!({
 5316                                    let project = editor.project.as_ref()?;
 5317                                    let dap_store = project.read(cx).dap_store();
 5318                                    let mut scenarios = vec![];
 5319                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5320                                    let buffer = buffer.read(cx);
 5321                                    let language = buffer.language()?;
 5322                                    let file = buffer.file();
 5323                                    let debug_adapter =
 5324                                        language_settings(language.name().into(), file, cx)
 5325                                            .debuggers
 5326                                            .first()
 5327                                            .map(SharedString::from)
 5328                                            .or_else(|| {
 5329                                                language
 5330                                                    .config()
 5331                                                    .debuggers
 5332                                                    .first()
 5333                                                    .map(SharedString::from)
 5334                                            })?;
 5335
 5336                                    dap_store.update(cx, |dap_store, cx| {
 5337                                        for (_, task) in &resolved_tasks.templates {
 5338                                            if let Some(scenario) = dap_store
 5339                                                .debug_scenario_for_build_task(
 5340                                                    task.original_task().clone(),
 5341                                                    debug_adapter.clone().into(),
 5342                                                    task.display_label().to_owned().into(),
 5343                                                    cx,
 5344                                                )
 5345                                            {
 5346                                                scenarios.push(scenario);
 5347                                            }
 5348                                        }
 5349                                    });
 5350                                    Some(scenarios)
 5351                                })
 5352                                .unwrap_or_default()
 5353                            } else {
 5354                                vec![]
 5355                            }
 5356                        })?;
 5357                        let spawn_straight_away = quick_launch
 5358                            && resolved_tasks
 5359                                .as_ref()
 5360                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5361                            && code_actions
 5362                                .as_ref()
 5363                                .map_or(true, |actions| actions.is_empty())
 5364                            && debug_scenarios.is_empty();
 5365                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5366                            *editor.context_menu.borrow_mut() =
 5367                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5368                                    buffer,
 5369                                    actions: CodeActionContents::new(
 5370                                        resolved_tasks,
 5371                                        code_actions,
 5372                                        debug_scenarios,
 5373                                        task_context.unwrap_or_default(),
 5374                                    ),
 5375                                    selected_item: Default::default(),
 5376                                    scroll_handle: UniformListScrollHandle::default(),
 5377                                    deployed_from_indicator,
 5378                                }));
 5379                            if spawn_straight_away {
 5380                                if let Some(task) = editor.confirm_code_action(
 5381                                    &ConfirmCodeAction { item_ix: Some(0) },
 5382                                    window,
 5383                                    cx,
 5384                                ) {
 5385                                    cx.notify();
 5386                                    return task;
 5387                                }
 5388                            }
 5389                            cx.notify();
 5390                            Task::ready(Ok(()))
 5391                        }) {
 5392                            task.await
 5393                        } else {
 5394                            Ok(())
 5395                        }
 5396                    }))
 5397                } else {
 5398                    Some(Task::ready(Ok(())))
 5399                }
 5400            })?;
 5401            if let Some(task) = spawned_test_task {
 5402                task.await?;
 5403            }
 5404
 5405            Ok::<_, anyhow::Error>(())
 5406        })
 5407        .detach_and_log_err(cx);
 5408    }
 5409
 5410    pub fn confirm_code_action(
 5411        &mut self,
 5412        action: &ConfirmCodeAction,
 5413        window: &mut Window,
 5414        cx: &mut Context<Self>,
 5415    ) -> Option<Task<Result<()>>> {
 5416        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5417
 5418        let actions_menu =
 5419            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5420                menu
 5421            } else {
 5422                return None;
 5423            };
 5424
 5425        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5426        let action = actions_menu.actions.get(action_ix)?;
 5427        let title = action.label();
 5428        let buffer = actions_menu.buffer;
 5429        let workspace = self.workspace()?;
 5430
 5431        match action {
 5432            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5433                workspace.update(cx, |workspace, cx| {
 5434                    workspace.schedule_resolved_task(
 5435                        task_source_kind,
 5436                        resolved_task,
 5437                        false,
 5438                        window,
 5439                        cx,
 5440                    );
 5441
 5442                    Some(Task::ready(Ok(())))
 5443                })
 5444            }
 5445            CodeActionsItem::CodeAction {
 5446                excerpt_id,
 5447                action,
 5448                provider,
 5449            } => {
 5450                let apply_code_action =
 5451                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5452                let workspace = workspace.downgrade();
 5453                Some(cx.spawn_in(window, async move |editor, cx| {
 5454                    let project_transaction = apply_code_action.await?;
 5455                    Self::open_project_transaction(
 5456                        &editor,
 5457                        workspace,
 5458                        project_transaction,
 5459                        title,
 5460                        cx,
 5461                    )
 5462                    .await
 5463                }))
 5464            }
 5465            CodeActionsItem::DebugScenario(scenario) => {
 5466                let context = actions_menu.actions.context.clone();
 5467
 5468                workspace.update(cx, |workspace, cx| {
 5469                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5470                });
 5471                Some(Task::ready(Ok(())))
 5472            }
 5473        }
 5474    }
 5475
 5476    pub async fn open_project_transaction(
 5477        this: &WeakEntity<Editor>,
 5478        workspace: WeakEntity<Workspace>,
 5479        transaction: ProjectTransaction,
 5480        title: String,
 5481        cx: &mut AsyncWindowContext,
 5482    ) -> Result<()> {
 5483        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5484        cx.update(|_, cx| {
 5485            entries.sort_unstable_by_key(|(buffer, _)| {
 5486                buffer.read(cx).file().map(|f| f.path().clone())
 5487            });
 5488        })?;
 5489
 5490        // If the project transaction's edits are all contained within this editor, then
 5491        // avoid opening a new editor to display them.
 5492
 5493        if let Some((buffer, transaction)) = entries.first() {
 5494            if entries.len() == 1 {
 5495                let excerpt = this.update(cx, |editor, cx| {
 5496                    editor
 5497                        .buffer()
 5498                        .read(cx)
 5499                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5500                })?;
 5501                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5502                    if excerpted_buffer == *buffer {
 5503                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5504                            let excerpt_range = excerpt_range.to_offset(buffer);
 5505                            buffer
 5506                                .edited_ranges_for_transaction::<usize>(transaction)
 5507                                .all(|range| {
 5508                                    excerpt_range.start <= range.start
 5509                                        && excerpt_range.end >= range.end
 5510                                })
 5511                        })?;
 5512
 5513                        if all_edits_within_excerpt {
 5514                            return Ok(());
 5515                        }
 5516                    }
 5517                }
 5518            }
 5519        } else {
 5520            return Ok(());
 5521        }
 5522
 5523        let mut ranges_to_highlight = Vec::new();
 5524        let excerpt_buffer = cx.new(|cx| {
 5525            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5526            for (buffer_handle, transaction) in &entries {
 5527                let edited_ranges = buffer_handle
 5528                    .read(cx)
 5529                    .edited_ranges_for_transaction::<Point>(transaction)
 5530                    .collect::<Vec<_>>();
 5531                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5532                    PathKey::for_buffer(buffer_handle, cx),
 5533                    buffer_handle.clone(),
 5534                    edited_ranges,
 5535                    DEFAULT_MULTIBUFFER_CONTEXT,
 5536                    cx,
 5537                );
 5538
 5539                ranges_to_highlight.extend(ranges);
 5540            }
 5541            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5542            multibuffer
 5543        })?;
 5544
 5545        workspace.update_in(cx, |workspace, window, cx| {
 5546            let project = workspace.project().clone();
 5547            let editor =
 5548                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5549            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5550            editor.update(cx, |editor, cx| {
 5551                editor.highlight_background::<Self>(
 5552                    &ranges_to_highlight,
 5553                    |theme| theme.editor_highlighted_line_background,
 5554                    cx,
 5555                );
 5556            });
 5557        })?;
 5558
 5559        Ok(())
 5560    }
 5561
 5562    pub fn clear_code_action_providers(&mut self) {
 5563        self.code_action_providers.clear();
 5564        self.available_code_actions.take();
 5565    }
 5566
 5567    pub fn add_code_action_provider(
 5568        &mut self,
 5569        provider: Rc<dyn CodeActionProvider>,
 5570        window: &mut Window,
 5571        cx: &mut Context<Self>,
 5572    ) {
 5573        if self
 5574            .code_action_providers
 5575            .iter()
 5576            .any(|existing_provider| existing_provider.id() == provider.id())
 5577        {
 5578            return;
 5579        }
 5580
 5581        self.code_action_providers.push(provider);
 5582        self.refresh_code_actions(window, cx);
 5583    }
 5584
 5585    pub fn remove_code_action_provider(
 5586        &mut self,
 5587        id: Arc<str>,
 5588        window: &mut Window,
 5589        cx: &mut Context<Self>,
 5590    ) {
 5591        self.code_action_providers
 5592            .retain(|provider| provider.id() != id);
 5593        self.refresh_code_actions(window, cx);
 5594    }
 5595
 5596    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5597        let newest_selection = self.selections.newest_anchor().clone();
 5598        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5599        let buffer = self.buffer.read(cx);
 5600        if newest_selection.head().diff_base_anchor.is_some() {
 5601            return None;
 5602        }
 5603        let (start_buffer, start) =
 5604            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5605        let (end_buffer, end) =
 5606            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5607        if start_buffer != end_buffer {
 5608            return None;
 5609        }
 5610
 5611        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5612            cx.background_executor()
 5613                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5614                .await;
 5615
 5616            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5617                let providers = this.code_action_providers.clone();
 5618                let tasks = this
 5619                    .code_action_providers
 5620                    .iter()
 5621                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5622                    .collect::<Vec<_>>();
 5623                (providers, tasks)
 5624            })?;
 5625
 5626            let mut actions = Vec::new();
 5627            for (provider, provider_actions) in
 5628                providers.into_iter().zip(future::join_all(tasks).await)
 5629            {
 5630                if let Some(provider_actions) = provider_actions.log_err() {
 5631                    actions.extend(provider_actions.into_iter().map(|action| {
 5632                        AvailableCodeAction {
 5633                            excerpt_id: newest_selection.start.excerpt_id,
 5634                            action,
 5635                            provider: provider.clone(),
 5636                        }
 5637                    }));
 5638                }
 5639            }
 5640
 5641            this.update(cx, |this, cx| {
 5642                this.available_code_actions = if actions.is_empty() {
 5643                    None
 5644                } else {
 5645                    Some((
 5646                        Location {
 5647                            buffer: start_buffer,
 5648                            range: start..end,
 5649                        },
 5650                        actions.into(),
 5651                    ))
 5652                };
 5653                cx.notify();
 5654            })
 5655        }));
 5656        None
 5657    }
 5658
 5659    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5660        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5661            self.show_git_blame_inline = false;
 5662
 5663            self.show_git_blame_inline_delay_task =
 5664                Some(cx.spawn_in(window, async move |this, cx| {
 5665                    cx.background_executor().timer(delay).await;
 5666
 5667                    this.update(cx, |this, cx| {
 5668                        this.show_git_blame_inline = true;
 5669                        cx.notify();
 5670                    })
 5671                    .log_err();
 5672                }));
 5673        }
 5674    }
 5675
 5676    fn show_blame_popover(
 5677        &mut self,
 5678        blame_entry: &BlameEntry,
 5679        position: gpui::Point<Pixels>,
 5680        cx: &mut Context<Self>,
 5681    ) {
 5682        if let Some(state) = &mut self.inline_blame_popover {
 5683            state.hide_task.take();
 5684            cx.notify();
 5685        } else {
 5686            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5687            let show_task = cx.spawn(async move |editor, cx| {
 5688                cx.background_executor()
 5689                    .timer(std::time::Duration::from_millis(delay))
 5690                    .await;
 5691                editor
 5692                    .update(cx, |editor, cx| {
 5693                        if let Some(state) = &mut editor.inline_blame_popover {
 5694                            state.show_task = None;
 5695                            cx.notify();
 5696                        }
 5697                    })
 5698                    .ok();
 5699            });
 5700            let Some(blame) = self.blame.as_ref() else {
 5701                return;
 5702            };
 5703            let blame = blame.read(cx);
 5704            let details = blame.details_for_entry(&blame_entry);
 5705            let markdown = cx.new(|cx| {
 5706                Markdown::new(
 5707                    details
 5708                        .as_ref()
 5709                        .map(|message| message.message.clone())
 5710                        .unwrap_or_default(),
 5711                    None,
 5712                    None,
 5713                    cx,
 5714                )
 5715            });
 5716            self.inline_blame_popover = Some(InlineBlamePopover {
 5717                position,
 5718                show_task: Some(show_task),
 5719                hide_task: None,
 5720                popover_bounds: None,
 5721                popover_state: InlineBlamePopoverState {
 5722                    scroll_handle: ScrollHandle::new(),
 5723                    commit_message: details,
 5724                    markdown,
 5725                },
 5726            });
 5727        }
 5728    }
 5729
 5730    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5731        if let Some(state) = &mut self.inline_blame_popover {
 5732            if state.show_task.is_some() {
 5733                self.inline_blame_popover.take();
 5734                cx.notify();
 5735            } else {
 5736                let hide_task = cx.spawn(async move |editor, cx| {
 5737                    cx.background_executor()
 5738                        .timer(std::time::Duration::from_millis(100))
 5739                        .await;
 5740                    editor
 5741                        .update(cx, |editor, cx| {
 5742                            editor.inline_blame_popover.take();
 5743                            cx.notify();
 5744                        })
 5745                        .ok();
 5746                });
 5747                state.hide_task = Some(hide_task);
 5748            }
 5749        }
 5750    }
 5751
 5752    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5753        if self.pending_rename.is_some() {
 5754            return None;
 5755        }
 5756
 5757        let provider = self.semantics_provider.clone()?;
 5758        let buffer = self.buffer.read(cx);
 5759        let newest_selection = self.selections.newest_anchor().clone();
 5760        let cursor_position = newest_selection.head();
 5761        let (cursor_buffer, cursor_buffer_position) =
 5762            buffer.text_anchor_for_position(cursor_position, cx)?;
 5763        let (tail_buffer, tail_buffer_position) =
 5764            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5765        if cursor_buffer != tail_buffer {
 5766            return None;
 5767        }
 5768
 5769        let snapshot = cursor_buffer.read(cx).snapshot();
 5770        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5771        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5772        if start_word_range != end_word_range {
 5773            self.document_highlights_task.take();
 5774            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5775            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5776            return None;
 5777        }
 5778
 5779        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5780        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5781            cx.background_executor()
 5782                .timer(Duration::from_millis(debounce))
 5783                .await;
 5784
 5785            let highlights = if let Some(highlights) = cx
 5786                .update(|cx| {
 5787                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5788                })
 5789                .ok()
 5790                .flatten()
 5791            {
 5792                highlights.await.log_err()
 5793            } else {
 5794                None
 5795            };
 5796
 5797            if let Some(highlights) = highlights {
 5798                this.update(cx, |this, cx| {
 5799                    if this.pending_rename.is_some() {
 5800                        return;
 5801                    }
 5802
 5803                    let buffer_id = cursor_position.buffer_id;
 5804                    let buffer = this.buffer.read(cx);
 5805                    if !buffer
 5806                        .text_anchor_for_position(cursor_position, cx)
 5807                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5808                    {
 5809                        return;
 5810                    }
 5811
 5812                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5813                    let mut write_ranges = Vec::new();
 5814                    let mut read_ranges = Vec::new();
 5815                    for highlight in highlights {
 5816                        for (excerpt_id, excerpt_range) in
 5817                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5818                        {
 5819                            let start = highlight
 5820                                .range
 5821                                .start
 5822                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5823                            let end = highlight
 5824                                .range
 5825                                .end
 5826                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5827                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5828                                continue;
 5829                            }
 5830
 5831                            let range = Anchor {
 5832                                buffer_id,
 5833                                excerpt_id,
 5834                                text_anchor: start,
 5835                                diff_base_anchor: None,
 5836                            }..Anchor {
 5837                                buffer_id,
 5838                                excerpt_id,
 5839                                text_anchor: end,
 5840                                diff_base_anchor: None,
 5841                            };
 5842                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5843                                write_ranges.push(range);
 5844                            } else {
 5845                                read_ranges.push(range);
 5846                            }
 5847                        }
 5848                    }
 5849
 5850                    this.highlight_background::<DocumentHighlightRead>(
 5851                        &read_ranges,
 5852                        |theme| theme.editor_document_highlight_read_background,
 5853                        cx,
 5854                    );
 5855                    this.highlight_background::<DocumentHighlightWrite>(
 5856                        &write_ranges,
 5857                        |theme| theme.editor_document_highlight_write_background,
 5858                        cx,
 5859                    );
 5860                    cx.notify();
 5861                })
 5862                .log_err();
 5863            }
 5864        }));
 5865        None
 5866    }
 5867
 5868    fn prepare_highlight_query_from_selection(
 5869        &mut self,
 5870        cx: &mut Context<Editor>,
 5871    ) -> Option<(String, Range<Anchor>)> {
 5872        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 5873            return None;
 5874        }
 5875        if !EditorSettings::get_global(cx).selection_highlight {
 5876            return None;
 5877        }
 5878        if self.selections.count() != 1 || self.selections.line_mode {
 5879            return None;
 5880        }
 5881        let selection = self.selections.newest::<Point>(cx);
 5882        if selection.is_empty() || selection.start.row != selection.end.row {
 5883            return None;
 5884        }
 5885        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5886        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 5887        let query = multi_buffer_snapshot
 5888            .text_for_range(selection_anchor_range.clone())
 5889            .collect::<String>();
 5890        if query.trim().is_empty() {
 5891            return None;
 5892        }
 5893        Some((query, selection_anchor_range))
 5894    }
 5895
 5896    fn update_selection_occurrence_highlights(
 5897        &mut self,
 5898        query_text: String,
 5899        query_range: Range<Anchor>,
 5900        multi_buffer_range_to_query: Range<Point>,
 5901        use_debounce: bool,
 5902        window: &mut Window,
 5903        cx: &mut Context<Editor>,
 5904    ) -> Task<()> {
 5905        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5906        cx.spawn_in(window, async move |editor, cx| {
 5907            if use_debounce {
 5908                cx.background_executor()
 5909                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 5910                    .await;
 5911            }
 5912            let match_task = cx.background_spawn(async move {
 5913                let buffer_ranges = multi_buffer_snapshot
 5914                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 5915                    .into_iter()
 5916                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 5917                let mut match_ranges = Vec::new();
 5918                let Ok(regex) = project::search::SearchQuery::text(
 5919                    query_text.clone(),
 5920                    false,
 5921                    false,
 5922                    false,
 5923                    Default::default(),
 5924                    Default::default(),
 5925                    false,
 5926                    None,
 5927                ) else {
 5928                    return Vec::default();
 5929                };
 5930                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 5931                    match_ranges.extend(
 5932                        regex
 5933                            .search(&buffer_snapshot, Some(search_range.clone()))
 5934                            .await
 5935                            .into_iter()
 5936                            .filter_map(|match_range| {
 5937                                let match_start = buffer_snapshot
 5938                                    .anchor_after(search_range.start + match_range.start);
 5939                                let match_end = buffer_snapshot
 5940                                    .anchor_before(search_range.start + match_range.end);
 5941                                let match_anchor_range = Anchor::range_in_buffer(
 5942                                    excerpt_id,
 5943                                    buffer_snapshot.remote_id(),
 5944                                    match_start..match_end,
 5945                                );
 5946                                (match_anchor_range != query_range).then_some(match_anchor_range)
 5947                            }),
 5948                    );
 5949                }
 5950                match_ranges
 5951            });
 5952            let match_ranges = match_task.await;
 5953            editor
 5954                .update_in(cx, |editor, _, cx| {
 5955                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5956                    if !match_ranges.is_empty() {
 5957                        editor.highlight_background::<SelectedTextHighlight>(
 5958                            &match_ranges,
 5959                            |theme| theme.editor_document_highlight_bracket_background,
 5960                            cx,
 5961                        )
 5962                    }
 5963                })
 5964                .log_err();
 5965        })
 5966    }
 5967
 5968    fn refresh_selected_text_highlights(
 5969        &mut self,
 5970        on_buffer_edit: bool,
 5971        window: &mut Window,
 5972        cx: &mut Context<Editor>,
 5973    ) {
 5974        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 5975        else {
 5976            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 5977            self.quick_selection_highlight_task.take();
 5978            self.debounced_selection_highlight_task.take();
 5979            return;
 5980        };
 5981        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5982        if on_buffer_edit
 5983            || self
 5984                .quick_selection_highlight_task
 5985                .as_ref()
 5986                .map_or(true, |(prev_anchor_range, _)| {
 5987                    prev_anchor_range != &query_range
 5988                })
 5989        {
 5990            let multi_buffer_visible_start = self
 5991                .scroll_manager
 5992                .anchor()
 5993                .anchor
 5994                .to_point(&multi_buffer_snapshot);
 5995            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5996                multi_buffer_visible_start
 5997                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5998                Bias::Left,
 5999            );
 6000            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6001            self.quick_selection_highlight_task = Some((
 6002                query_range.clone(),
 6003                self.update_selection_occurrence_highlights(
 6004                    query_text.clone(),
 6005                    query_range.clone(),
 6006                    multi_buffer_visible_range,
 6007                    false,
 6008                    window,
 6009                    cx,
 6010                ),
 6011            ));
 6012        }
 6013        if on_buffer_edit
 6014            || self
 6015                .debounced_selection_highlight_task
 6016                .as_ref()
 6017                .map_or(true, |(prev_anchor_range, _)| {
 6018                    prev_anchor_range != &query_range
 6019                })
 6020        {
 6021            let multi_buffer_start = multi_buffer_snapshot
 6022                .anchor_before(0)
 6023                .to_point(&multi_buffer_snapshot);
 6024            let multi_buffer_end = multi_buffer_snapshot
 6025                .anchor_after(multi_buffer_snapshot.len())
 6026                .to_point(&multi_buffer_snapshot);
 6027            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6028            self.debounced_selection_highlight_task = Some((
 6029                query_range.clone(),
 6030                self.update_selection_occurrence_highlights(
 6031                    query_text,
 6032                    query_range,
 6033                    multi_buffer_full_range,
 6034                    true,
 6035                    window,
 6036                    cx,
 6037                ),
 6038            ));
 6039        }
 6040    }
 6041
 6042    pub fn refresh_inline_completion(
 6043        &mut self,
 6044        debounce: bool,
 6045        user_requested: bool,
 6046        window: &mut Window,
 6047        cx: &mut Context<Self>,
 6048    ) -> Option<()> {
 6049        let provider = self.edit_prediction_provider()?;
 6050        let cursor = self.selections.newest_anchor().head();
 6051        let (buffer, cursor_buffer_position) =
 6052            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6053
 6054        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6055            self.discard_inline_completion(false, cx);
 6056            return None;
 6057        }
 6058
 6059        if !user_requested
 6060            && (!self.should_show_edit_predictions()
 6061                || !self.is_focused(window)
 6062                || buffer.read(cx).is_empty())
 6063        {
 6064            self.discard_inline_completion(false, cx);
 6065            return None;
 6066        }
 6067
 6068        self.update_visible_inline_completion(window, cx);
 6069        provider.refresh(
 6070            self.project.clone(),
 6071            buffer,
 6072            cursor_buffer_position,
 6073            debounce,
 6074            cx,
 6075        );
 6076        Some(())
 6077    }
 6078
 6079    fn show_edit_predictions_in_menu(&self) -> bool {
 6080        match self.edit_prediction_settings {
 6081            EditPredictionSettings::Disabled => false,
 6082            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6083        }
 6084    }
 6085
 6086    pub fn edit_predictions_enabled(&self) -> bool {
 6087        match self.edit_prediction_settings {
 6088            EditPredictionSettings::Disabled => false,
 6089            EditPredictionSettings::Enabled { .. } => true,
 6090        }
 6091    }
 6092
 6093    fn edit_prediction_requires_modifier(&self) -> bool {
 6094        match self.edit_prediction_settings {
 6095            EditPredictionSettings::Disabled => false,
 6096            EditPredictionSettings::Enabled {
 6097                preview_requires_modifier,
 6098                ..
 6099            } => preview_requires_modifier,
 6100        }
 6101    }
 6102
 6103    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6104        if self.edit_prediction_provider.is_none() {
 6105            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6106        } else {
 6107            let selection = self.selections.newest_anchor();
 6108            let cursor = selection.head();
 6109
 6110            if let Some((buffer, cursor_buffer_position)) =
 6111                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6112            {
 6113                self.edit_prediction_settings =
 6114                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6115            }
 6116        }
 6117    }
 6118
 6119    fn edit_prediction_settings_at_position(
 6120        &self,
 6121        buffer: &Entity<Buffer>,
 6122        buffer_position: language::Anchor,
 6123        cx: &App,
 6124    ) -> EditPredictionSettings {
 6125        if !self.mode.is_full()
 6126            || !self.show_inline_completions_override.unwrap_or(true)
 6127            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6128        {
 6129            return EditPredictionSettings::Disabled;
 6130        }
 6131
 6132        let buffer = buffer.read(cx);
 6133
 6134        let file = buffer.file();
 6135
 6136        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6137            return EditPredictionSettings::Disabled;
 6138        };
 6139
 6140        let by_provider = matches!(
 6141            self.menu_inline_completions_policy,
 6142            MenuInlineCompletionsPolicy::ByProvider
 6143        );
 6144
 6145        let show_in_menu = by_provider
 6146            && self
 6147                .edit_prediction_provider
 6148                .as_ref()
 6149                .map_or(false, |provider| {
 6150                    provider.provider.show_completions_in_menu()
 6151                });
 6152
 6153        let preview_requires_modifier =
 6154            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6155
 6156        EditPredictionSettings::Enabled {
 6157            show_in_menu,
 6158            preview_requires_modifier,
 6159        }
 6160    }
 6161
 6162    fn should_show_edit_predictions(&self) -> bool {
 6163        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6164    }
 6165
 6166    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6167        matches!(
 6168            self.edit_prediction_preview,
 6169            EditPredictionPreview::Active { .. }
 6170        )
 6171    }
 6172
 6173    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6174        let cursor = self.selections.newest_anchor().head();
 6175        if let Some((buffer, cursor_position)) =
 6176            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6177        {
 6178            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6179        } else {
 6180            false
 6181        }
 6182    }
 6183
 6184    pub fn supports_minimap(&self, cx: &App) -> bool {
 6185        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6186    }
 6187
 6188    fn edit_predictions_enabled_in_buffer(
 6189        &self,
 6190        buffer: &Entity<Buffer>,
 6191        buffer_position: language::Anchor,
 6192        cx: &App,
 6193    ) -> bool {
 6194        maybe!({
 6195            if self.read_only(cx) {
 6196                return Some(false);
 6197            }
 6198            let provider = self.edit_prediction_provider()?;
 6199            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6200                return Some(false);
 6201            }
 6202            let buffer = buffer.read(cx);
 6203            let Some(file) = buffer.file() else {
 6204                return Some(true);
 6205            };
 6206            let settings = all_language_settings(Some(file), cx);
 6207            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6208        })
 6209        .unwrap_or(false)
 6210    }
 6211
 6212    fn cycle_inline_completion(
 6213        &mut self,
 6214        direction: Direction,
 6215        window: &mut Window,
 6216        cx: &mut Context<Self>,
 6217    ) -> Option<()> {
 6218        let provider = self.edit_prediction_provider()?;
 6219        let cursor = self.selections.newest_anchor().head();
 6220        let (buffer, cursor_buffer_position) =
 6221            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6222        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6223            return None;
 6224        }
 6225
 6226        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6227        self.update_visible_inline_completion(window, cx);
 6228
 6229        Some(())
 6230    }
 6231
 6232    pub fn show_inline_completion(
 6233        &mut self,
 6234        _: &ShowEditPrediction,
 6235        window: &mut Window,
 6236        cx: &mut Context<Self>,
 6237    ) {
 6238        if !self.has_active_inline_completion() {
 6239            self.refresh_inline_completion(false, true, window, cx);
 6240            return;
 6241        }
 6242
 6243        self.update_visible_inline_completion(window, cx);
 6244    }
 6245
 6246    pub fn display_cursor_names(
 6247        &mut self,
 6248        _: &DisplayCursorNames,
 6249        window: &mut Window,
 6250        cx: &mut Context<Self>,
 6251    ) {
 6252        self.show_cursor_names(window, cx);
 6253    }
 6254
 6255    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6256        self.show_cursor_names = true;
 6257        cx.notify();
 6258        cx.spawn_in(window, async move |this, cx| {
 6259            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6260            this.update(cx, |this, cx| {
 6261                this.show_cursor_names = false;
 6262                cx.notify()
 6263            })
 6264            .ok()
 6265        })
 6266        .detach();
 6267    }
 6268
 6269    pub fn next_edit_prediction(
 6270        &mut self,
 6271        _: &NextEditPrediction,
 6272        window: &mut Window,
 6273        cx: &mut Context<Self>,
 6274    ) {
 6275        if self.has_active_inline_completion() {
 6276            self.cycle_inline_completion(Direction::Next, window, cx);
 6277        } else {
 6278            let is_copilot_disabled = self
 6279                .refresh_inline_completion(false, true, window, cx)
 6280                .is_none();
 6281            if is_copilot_disabled {
 6282                cx.propagate();
 6283            }
 6284        }
 6285    }
 6286
 6287    pub fn previous_edit_prediction(
 6288        &mut self,
 6289        _: &PreviousEditPrediction,
 6290        window: &mut Window,
 6291        cx: &mut Context<Self>,
 6292    ) {
 6293        if self.has_active_inline_completion() {
 6294            self.cycle_inline_completion(Direction::Prev, window, cx);
 6295        } else {
 6296            let is_copilot_disabled = self
 6297                .refresh_inline_completion(false, true, window, cx)
 6298                .is_none();
 6299            if is_copilot_disabled {
 6300                cx.propagate();
 6301            }
 6302        }
 6303    }
 6304
 6305    pub fn accept_edit_prediction(
 6306        &mut self,
 6307        _: &AcceptEditPrediction,
 6308        window: &mut Window,
 6309        cx: &mut Context<Self>,
 6310    ) {
 6311        if self.show_edit_predictions_in_menu() {
 6312            self.hide_context_menu(window, cx);
 6313        }
 6314
 6315        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6316            return;
 6317        };
 6318
 6319        self.report_inline_completion_event(
 6320            active_inline_completion.completion_id.clone(),
 6321            true,
 6322            cx,
 6323        );
 6324
 6325        match &active_inline_completion.completion {
 6326            InlineCompletion::Move { target, .. } => {
 6327                let target = *target;
 6328
 6329                if let Some(position_map) = &self.last_position_map {
 6330                    if position_map
 6331                        .visible_row_range
 6332                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6333                        || !self.edit_prediction_requires_modifier()
 6334                    {
 6335                        self.unfold_ranges(&[target..target], true, false, cx);
 6336                        // Note that this is also done in vim's handler of the Tab action.
 6337                        self.change_selections(
 6338                            Some(Autoscroll::newest()),
 6339                            window,
 6340                            cx,
 6341                            |selections| {
 6342                                selections.select_anchor_ranges([target..target]);
 6343                            },
 6344                        );
 6345                        self.clear_row_highlights::<EditPredictionPreview>();
 6346
 6347                        self.edit_prediction_preview
 6348                            .set_previous_scroll_position(None);
 6349                    } else {
 6350                        self.edit_prediction_preview
 6351                            .set_previous_scroll_position(Some(
 6352                                position_map.snapshot.scroll_anchor,
 6353                            ));
 6354
 6355                        self.highlight_rows::<EditPredictionPreview>(
 6356                            target..target,
 6357                            cx.theme().colors().editor_highlighted_line_background,
 6358                            RowHighlightOptions {
 6359                                autoscroll: true,
 6360                                ..Default::default()
 6361                            },
 6362                            cx,
 6363                        );
 6364                        self.request_autoscroll(Autoscroll::fit(), cx);
 6365                    }
 6366                }
 6367            }
 6368            InlineCompletion::Edit { edits, .. } => {
 6369                if let Some(provider) = self.edit_prediction_provider() {
 6370                    provider.accept(cx);
 6371                }
 6372
 6373                let snapshot = self.buffer.read(cx).snapshot(cx);
 6374                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6375
 6376                self.buffer.update(cx, |buffer, cx| {
 6377                    buffer.edit(edits.iter().cloned(), None, cx)
 6378                });
 6379
 6380                self.change_selections(None, window, cx, |s| {
 6381                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6382                });
 6383
 6384                self.update_visible_inline_completion(window, cx);
 6385                if self.active_inline_completion.is_none() {
 6386                    self.refresh_inline_completion(true, true, window, cx);
 6387                }
 6388
 6389                cx.notify();
 6390            }
 6391        }
 6392
 6393        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6394    }
 6395
 6396    pub fn accept_partial_inline_completion(
 6397        &mut self,
 6398        _: &AcceptPartialEditPrediction,
 6399        window: &mut Window,
 6400        cx: &mut Context<Self>,
 6401    ) {
 6402        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6403            return;
 6404        };
 6405        if self.selections.count() != 1 {
 6406            return;
 6407        }
 6408
 6409        self.report_inline_completion_event(
 6410            active_inline_completion.completion_id.clone(),
 6411            true,
 6412            cx,
 6413        );
 6414
 6415        match &active_inline_completion.completion {
 6416            InlineCompletion::Move { target, .. } => {
 6417                let target = *target;
 6418                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6419                    selections.select_anchor_ranges([target..target]);
 6420                });
 6421            }
 6422            InlineCompletion::Edit { edits, .. } => {
 6423                // Find an insertion that starts at the cursor position.
 6424                let snapshot = self.buffer.read(cx).snapshot(cx);
 6425                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6426                let insertion = edits.iter().find_map(|(range, text)| {
 6427                    let range = range.to_offset(&snapshot);
 6428                    if range.is_empty() && range.start == cursor_offset {
 6429                        Some(text)
 6430                    } else {
 6431                        None
 6432                    }
 6433                });
 6434
 6435                if let Some(text) = insertion {
 6436                    let mut partial_completion = text
 6437                        .chars()
 6438                        .by_ref()
 6439                        .take_while(|c| c.is_alphabetic())
 6440                        .collect::<String>();
 6441                    if partial_completion.is_empty() {
 6442                        partial_completion = text
 6443                            .chars()
 6444                            .by_ref()
 6445                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6446                            .collect::<String>();
 6447                    }
 6448
 6449                    cx.emit(EditorEvent::InputHandled {
 6450                        utf16_range_to_replace: None,
 6451                        text: partial_completion.clone().into(),
 6452                    });
 6453
 6454                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6455
 6456                    self.refresh_inline_completion(true, true, window, cx);
 6457                    cx.notify();
 6458                } else {
 6459                    self.accept_edit_prediction(&Default::default(), window, cx);
 6460                }
 6461            }
 6462        }
 6463    }
 6464
 6465    fn discard_inline_completion(
 6466        &mut self,
 6467        should_report_inline_completion_event: bool,
 6468        cx: &mut Context<Self>,
 6469    ) -> bool {
 6470        if should_report_inline_completion_event {
 6471            let completion_id = self
 6472                .active_inline_completion
 6473                .as_ref()
 6474                .and_then(|active_completion| active_completion.completion_id.clone());
 6475
 6476            self.report_inline_completion_event(completion_id, false, cx);
 6477        }
 6478
 6479        if let Some(provider) = self.edit_prediction_provider() {
 6480            provider.discard(cx);
 6481        }
 6482
 6483        self.take_active_inline_completion(cx)
 6484    }
 6485
 6486    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6487        let Some(provider) = self.edit_prediction_provider() else {
 6488            return;
 6489        };
 6490
 6491        let Some((_, buffer, _)) = self
 6492            .buffer
 6493            .read(cx)
 6494            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6495        else {
 6496            return;
 6497        };
 6498
 6499        let extension = buffer
 6500            .read(cx)
 6501            .file()
 6502            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6503
 6504        let event_type = match accepted {
 6505            true => "Edit Prediction Accepted",
 6506            false => "Edit Prediction Discarded",
 6507        };
 6508        telemetry::event!(
 6509            event_type,
 6510            provider = provider.name(),
 6511            prediction_id = id,
 6512            suggestion_accepted = accepted,
 6513            file_extension = extension,
 6514        );
 6515    }
 6516
 6517    pub fn has_active_inline_completion(&self) -> bool {
 6518        self.active_inline_completion.is_some()
 6519    }
 6520
 6521    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6522        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6523            return false;
 6524        };
 6525
 6526        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6527        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6528        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6529        true
 6530    }
 6531
 6532    /// Returns true when we're displaying the edit prediction popover below the cursor
 6533    /// like we are not previewing and the LSP autocomplete menu is visible
 6534    /// or we are in `when_holding_modifier` mode.
 6535    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6536        if self.edit_prediction_preview_is_active()
 6537            || !self.show_edit_predictions_in_menu()
 6538            || !self.edit_predictions_enabled()
 6539        {
 6540            return false;
 6541        }
 6542
 6543        if self.has_visible_completions_menu() {
 6544            return true;
 6545        }
 6546
 6547        has_completion && self.edit_prediction_requires_modifier()
 6548    }
 6549
 6550    fn handle_modifiers_changed(
 6551        &mut self,
 6552        modifiers: Modifiers,
 6553        position_map: &PositionMap,
 6554        window: &mut Window,
 6555        cx: &mut Context<Self>,
 6556    ) {
 6557        if self.show_edit_predictions_in_menu() {
 6558            self.update_edit_prediction_preview(&modifiers, window, cx);
 6559        }
 6560
 6561        self.update_selection_mode(&modifiers, position_map, window, cx);
 6562
 6563        let mouse_position = window.mouse_position();
 6564        if !position_map.text_hitbox.is_hovered(window) {
 6565            return;
 6566        }
 6567
 6568        self.update_hovered_link(
 6569            position_map.point_for_position(mouse_position),
 6570            &position_map.snapshot,
 6571            modifiers,
 6572            window,
 6573            cx,
 6574        )
 6575    }
 6576
 6577    fn update_selection_mode(
 6578        &mut self,
 6579        modifiers: &Modifiers,
 6580        position_map: &PositionMap,
 6581        window: &mut Window,
 6582        cx: &mut Context<Self>,
 6583    ) {
 6584        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6585            return;
 6586        }
 6587
 6588        let mouse_position = window.mouse_position();
 6589        let point_for_position = position_map.point_for_position(mouse_position);
 6590        let position = point_for_position.previous_valid;
 6591
 6592        self.select(
 6593            SelectPhase::BeginColumnar {
 6594                position,
 6595                reset: false,
 6596                goal_column: point_for_position.exact_unclipped.column(),
 6597            },
 6598            window,
 6599            cx,
 6600        );
 6601    }
 6602
 6603    fn update_edit_prediction_preview(
 6604        &mut self,
 6605        modifiers: &Modifiers,
 6606        window: &mut Window,
 6607        cx: &mut Context<Self>,
 6608    ) {
 6609        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6610        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6611            return;
 6612        };
 6613
 6614        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6615            if matches!(
 6616                self.edit_prediction_preview,
 6617                EditPredictionPreview::Inactive { .. }
 6618            ) {
 6619                self.edit_prediction_preview = EditPredictionPreview::Active {
 6620                    previous_scroll_position: None,
 6621                    since: Instant::now(),
 6622                };
 6623
 6624                self.update_visible_inline_completion(window, cx);
 6625                cx.notify();
 6626            }
 6627        } else if let EditPredictionPreview::Active {
 6628            previous_scroll_position,
 6629            since,
 6630        } = self.edit_prediction_preview
 6631        {
 6632            if let (Some(previous_scroll_position), Some(position_map)) =
 6633                (previous_scroll_position, self.last_position_map.as_ref())
 6634            {
 6635                self.set_scroll_position(
 6636                    previous_scroll_position
 6637                        .scroll_position(&position_map.snapshot.display_snapshot),
 6638                    window,
 6639                    cx,
 6640                );
 6641            }
 6642
 6643            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6644                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6645            };
 6646            self.clear_row_highlights::<EditPredictionPreview>();
 6647            self.update_visible_inline_completion(window, cx);
 6648            cx.notify();
 6649        }
 6650    }
 6651
 6652    fn update_visible_inline_completion(
 6653        &mut self,
 6654        _window: &mut Window,
 6655        cx: &mut Context<Self>,
 6656    ) -> Option<()> {
 6657        let selection = self.selections.newest_anchor();
 6658        let cursor = selection.head();
 6659        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6660        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6661        let excerpt_id = cursor.excerpt_id;
 6662
 6663        let show_in_menu = self.show_edit_predictions_in_menu();
 6664        let completions_menu_has_precedence = !show_in_menu
 6665            && (self.context_menu.borrow().is_some()
 6666                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6667
 6668        if completions_menu_has_precedence
 6669            || !offset_selection.is_empty()
 6670            || self
 6671                .active_inline_completion
 6672                .as_ref()
 6673                .map_or(false, |completion| {
 6674                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6675                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6676                    !invalidation_range.contains(&offset_selection.head())
 6677                })
 6678        {
 6679            self.discard_inline_completion(false, cx);
 6680            return None;
 6681        }
 6682
 6683        self.take_active_inline_completion(cx);
 6684        let Some(provider) = self.edit_prediction_provider() else {
 6685            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6686            return None;
 6687        };
 6688
 6689        let (buffer, cursor_buffer_position) =
 6690            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6691
 6692        self.edit_prediction_settings =
 6693            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6694
 6695        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6696
 6697        if self.edit_prediction_indent_conflict {
 6698            let cursor_point = cursor.to_point(&multibuffer);
 6699
 6700            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6701
 6702            if let Some((_, indent)) = indents.iter().next() {
 6703                if indent.len == cursor_point.column {
 6704                    self.edit_prediction_indent_conflict = false;
 6705                }
 6706            }
 6707        }
 6708
 6709        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6710        let edits = inline_completion
 6711            .edits
 6712            .into_iter()
 6713            .flat_map(|(range, new_text)| {
 6714                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6715                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6716                Some((start..end, new_text))
 6717            })
 6718            .collect::<Vec<_>>();
 6719        if edits.is_empty() {
 6720            return None;
 6721        }
 6722
 6723        let first_edit_start = edits.first().unwrap().0.start;
 6724        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6725        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6726
 6727        let last_edit_end = edits.last().unwrap().0.end;
 6728        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6729        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6730
 6731        let cursor_row = cursor.to_point(&multibuffer).row;
 6732
 6733        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6734
 6735        let mut inlay_ids = Vec::new();
 6736        let invalidation_row_range;
 6737        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6738            Some(cursor_row..edit_end_row)
 6739        } else if cursor_row > edit_end_row {
 6740            Some(edit_start_row..cursor_row)
 6741        } else {
 6742            None
 6743        };
 6744        let is_move =
 6745            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6746        let completion = if is_move {
 6747            invalidation_row_range =
 6748                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6749            let target = first_edit_start;
 6750            InlineCompletion::Move { target, snapshot }
 6751        } else {
 6752            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6753                && !self.inline_completions_hidden_for_vim_mode;
 6754
 6755            if show_completions_in_buffer {
 6756                if edits
 6757                    .iter()
 6758                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6759                {
 6760                    let mut inlays = Vec::new();
 6761                    for (range, new_text) in &edits {
 6762                        let inlay = Inlay::inline_completion(
 6763                            post_inc(&mut self.next_inlay_id),
 6764                            range.start,
 6765                            new_text.as_str(),
 6766                        );
 6767                        inlay_ids.push(inlay.id);
 6768                        inlays.push(inlay);
 6769                    }
 6770
 6771                    self.splice_inlays(&[], inlays, cx);
 6772                } else {
 6773                    let background_color = cx.theme().status().deleted_background;
 6774                    self.highlight_text::<InlineCompletionHighlight>(
 6775                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6776                        HighlightStyle {
 6777                            background_color: Some(background_color),
 6778                            ..Default::default()
 6779                        },
 6780                        cx,
 6781                    );
 6782                }
 6783            }
 6784
 6785            invalidation_row_range = edit_start_row..edit_end_row;
 6786
 6787            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6788                if provider.show_tab_accept_marker() {
 6789                    EditDisplayMode::TabAccept
 6790                } else {
 6791                    EditDisplayMode::Inline
 6792                }
 6793            } else {
 6794                EditDisplayMode::DiffPopover
 6795            };
 6796
 6797            InlineCompletion::Edit {
 6798                edits,
 6799                edit_preview: inline_completion.edit_preview,
 6800                display_mode,
 6801                snapshot,
 6802            }
 6803        };
 6804
 6805        let invalidation_range = multibuffer
 6806            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6807            ..multibuffer.anchor_after(Point::new(
 6808                invalidation_row_range.end,
 6809                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6810            ));
 6811
 6812        self.stale_inline_completion_in_menu = None;
 6813        self.active_inline_completion = Some(InlineCompletionState {
 6814            inlay_ids,
 6815            completion,
 6816            completion_id: inline_completion.id,
 6817            invalidation_range,
 6818        });
 6819
 6820        cx.notify();
 6821
 6822        Some(())
 6823    }
 6824
 6825    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6826        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6827    }
 6828
 6829    fn clear_tasks(&mut self) {
 6830        self.tasks.clear()
 6831    }
 6832
 6833    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6834        if self.tasks.insert(key, value).is_some() {
 6835            // This case should hopefully be rare, but just in case...
 6836            log::error!(
 6837                "multiple different run targets found on a single line, only the last target will be rendered"
 6838            )
 6839        }
 6840    }
 6841
 6842    /// Get all display points of breakpoints that will be rendered within editor
 6843    ///
 6844    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6845    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6846    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6847    fn active_breakpoints(
 6848        &self,
 6849        range: Range<DisplayRow>,
 6850        window: &mut Window,
 6851        cx: &mut Context<Self>,
 6852    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 6853        let mut breakpoint_display_points = HashMap::default();
 6854
 6855        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 6856            return breakpoint_display_points;
 6857        };
 6858
 6859        let snapshot = self.snapshot(window, cx);
 6860
 6861        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 6862        let Some(project) = self.project.as_ref() else {
 6863            return breakpoint_display_points;
 6864        };
 6865
 6866        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 6867            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 6868
 6869        for (buffer_snapshot, range, excerpt_id) in
 6870            multi_buffer_snapshot.range_to_buffer_ranges(range)
 6871        {
 6872            let Some(buffer) = project.read_with(cx, |this, cx| {
 6873                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 6874            }) else {
 6875                continue;
 6876            };
 6877            let breakpoints = breakpoint_store.read(cx).breakpoints(
 6878                &buffer,
 6879                Some(
 6880                    buffer_snapshot.anchor_before(range.start)
 6881                        ..buffer_snapshot.anchor_after(range.end),
 6882                ),
 6883                buffer_snapshot,
 6884                cx,
 6885            );
 6886            for (breakpoint, state) in breakpoints {
 6887                let multi_buffer_anchor =
 6888                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 6889                let position = multi_buffer_anchor
 6890                    .to_point(&multi_buffer_snapshot)
 6891                    .to_display_point(&snapshot);
 6892
 6893                breakpoint_display_points.insert(
 6894                    position.row(),
 6895                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 6896                );
 6897            }
 6898        }
 6899
 6900        breakpoint_display_points
 6901    }
 6902
 6903    fn breakpoint_context_menu(
 6904        &self,
 6905        anchor: Anchor,
 6906        window: &mut Window,
 6907        cx: &mut Context<Self>,
 6908    ) -> Entity<ui::ContextMenu> {
 6909        let weak_editor = cx.weak_entity();
 6910        let focus_handle = self.focus_handle(cx);
 6911
 6912        let row = self
 6913            .buffer
 6914            .read(cx)
 6915            .snapshot(cx)
 6916            .summary_for_anchor::<Point>(&anchor)
 6917            .row;
 6918
 6919        let breakpoint = self
 6920            .breakpoint_at_row(row, window, cx)
 6921            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 6922
 6923        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 6924            "Edit Log Breakpoint"
 6925        } else {
 6926            "Set Log Breakpoint"
 6927        };
 6928
 6929        let condition_breakpoint_msg = if breakpoint
 6930            .as_ref()
 6931            .is_some_and(|bp| bp.1.condition.is_some())
 6932        {
 6933            "Edit Condition Breakpoint"
 6934        } else {
 6935            "Set Condition Breakpoint"
 6936        };
 6937
 6938        let hit_condition_breakpoint_msg = if breakpoint
 6939            .as_ref()
 6940            .is_some_and(|bp| bp.1.hit_condition.is_some())
 6941        {
 6942            "Edit Hit Condition Breakpoint"
 6943        } else {
 6944            "Set Hit Condition Breakpoint"
 6945        };
 6946
 6947        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 6948            "Unset Breakpoint"
 6949        } else {
 6950            "Set Breakpoint"
 6951        };
 6952
 6953        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 6954            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 6955
 6956        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 6957            BreakpointState::Enabled => Some("Disable"),
 6958            BreakpointState::Disabled => Some("Enable"),
 6959        });
 6960
 6961        let (anchor, breakpoint) =
 6962            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 6963
 6964        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 6965            menu.on_blur_subscription(Subscription::new(|| {}))
 6966                .context(focus_handle)
 6967                .when(run_to_cursor, |this| {
 6968                    let weak_editor = weak_editor.clone();
 6969                    this.entry("Run to cursor", None, move |window, cx| {
 6970                        weak_editor
 6971                            .update(cx, |editor, cx| {
 6972                                editor.change_selections(None, window, cx, |s| {
 6973                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 6974                                });
 6975                            })
 6976                            .ok();
 6977
 6978                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 6979                    })
 6980                    .separator()
 6981                })
 6982                .when_some(toggle_state_msg, |this, msg| {
 6983                    this.entry(msg, None, {
 6984                        let weak_editor = weak_editor.clone();
 6985                        let breakpoint = breakpoint.clone();
 6986                        move |_window, cx| {
 6987                            weak_editor
 6988                                .update(cx, |this, cx| {
 6989                                    this.edit_breakpoint_at_anchor(
 6990                                        anchor,
 6991                                        breakpoint.as_ref().clone(),
 6992                                        BreakpointEditAction::InvertState,
 6993                                        cx,
 6994                                    );
 6995                                })
 6996                                .log_err();
 6997                        }
 6998                    })
 6999                })
 7000                .entry(set_breakpoint_msg, None, {
 7001                    let weak_editor = weak_editor.clone();
 7002                    let breakpoint = breakpoint.clone();
 7003                    move |_window, cx| {
 7004                        weak_editor
 7005                            .update(cx, |this, cx| {
 7006                                this.edit_breakpoint_at_anchor(
 7007                                    anchor,
 7008                                    breakpoint.as_ref().clone(),
 7009                                    BreakpointEditAction::Toggle,
 7010                                    cx,
 7011                                );
 7012                            })
 7013                            .log_err();
 7014                    }
 7015                })
 7016                .entry(log_breakpoint_msg, None, {
 7017                    let breakpoint = breakpoint.clone();
 7018                    let weak_editor = weak_editor.clone();
 7019                    move |window, cx| {
 7020                        weak_editor
 7021                            .update(cx, |this, cx| {
 7022                                this.add_edit_breakpoint_block(
 7023                                    anchor,
 7024                                    breakpoint.as_ref(),
 7025                                    BreakpointPromptEditAction::Log,
 7026                                    window,
 7027                                    cx,
 7028                                );
 7029                            })
 7030                            .log_err();
 7031                    }
 7032                })
 7033                .entry(condition_breakpoint_msg, None, {
 7034                    let breakpoint = breakpoint.clone();
 7035                    let weak_editor = weak_editor.clone();
 7036                    move |window, cx| {
 7037                        weak_editor
 7038                            .update(cx, |this, cx| {
 7039                                this.add_edit_breakpoint_block(
 7040                                    anchor,
 7041                                    breakpoint.as_ref(),
 7042                                    BreakpointPromptEditAction::Condition,
 7043                                    window,
 7044                                    cx,
 7045                                );
 7046                            })
 7047                            .log_err();
 7048                    }
 7049                })
 7050                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7051                    weak_editor
 7052                        .update(cx, |this, cx| {
 7053                            this.add_edit_breakpoint_block(
 7054                                anchor,
 7055                                breakpoint.as_ref(),
 7056                                BreakpointPromptEditAction::HitCondition,
 7057                                window,
 7058                                cx,
 7059                            );
 7060                        })
 7061                        .log_err();
 7062                })
 7063        })
 7064    }
 7065
 7066    fn render_breakpoint(
 7067        &self,
 7068        position: Anchor,
 7069        row: DisplayRow,
 7070        breakpoint: &Breakpoint,
 7071        state: Option<BreakpointSessionState>,
 7072        cx: &mut Context<Self>,
 7073    ) -> IconButton {
 7074        let is_rejected = state.is_some_and(|s| !s.verified);
 7075        // Is it a breakpoint that shows up when hovering over gutter?
 7076        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7077            (false, false),
 7078            |PhantomBreakpointIndicator {
 7079                 is_active,
 7080                 display_row,
 7081                 collides_with_existing_breakpoint,
 7082             }| {
 7083                (
 7084                    is_active && display_row == row,
 7085                    collides_with_existing_breakpoint,
 7086                )
 7087            },
 7088        );
 7089
 7090        let (color, icon) = {
 7091            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7092                (false, false) => ui::IconName::DebugBreakpoint,
 7093                (true, false) => ui::IconName::DebugLogBreakpoint,
 7094                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7095                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7096            };
 7097
 7098            let color = if is_phantom {
 7099                Color::Hint
 7100            } else if is_rejected {
 7101                Color::Disabled
 7102            } else {
 7103                Color::Debugger
 7104            };
 7105
 7106            (color, icon)
 7107        };
 7108
 7109        let breakpoint = Arc::from(breakpoint.clone());
 7110
 7111        let alt_as_text = gpui::Keystroke {
 7112            modifiers: Modifiers::secondary_key(),
 7113            ..Default::default()
 7114        };
 7115        let primary_action_text = if breakpoint.is_disabled() {
 7116            "enable"
 7117        } else if is_phantom && !collides_with_existing {
 7118            "set"
 7119        } else {
 7120            "unset"
 7121        };
 7122        let mut primary_text = format!("Click to {primary_action_text}");
 7123        if collides_with_existing && !breakpoint.is_disabled() {
 7124            use std::fmt::Write;
 7125            write!(primary_text, ", {alt_as_text}-click to disable").ok();
 7126        }
 7127        let primary_text = SharedString::from(primary_text);
 7128        let focus_handle = self.focus_handle.clone();
 7129
 7130        let meta = if is_rejected {
 7131            "No executable code is associated with this line."
 7132        } else {
 7133            "Right-click for more options."
 7134        };
 7135        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7136            .icon_size(IconSize::XSmall)
 7137            .size(ui::ButtonSize::None)
 7138            .when(is_rejected, |this| {
 7139                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7140            })
 7141            .icon_color(color)
 7142            .style(ButtonStyle::Transparent)
 7143            .on_click(cx.listener({
 7144                let breakpoint = breakpoint.clone();
 7145
 7146                move |editor, event: &ClickEvent, window, cx| {
 7147                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7148                        BreakpointEditAction::InvertState
 7149                    } else {
 7150                        BreakpointEditAction::Toggle
 7151                    };
 7152
 7153                    window.focus(&editor.focus_handle(cx));
 7154                    editor.edit_breakpoint_at_anchor(
 7155                        position,
 7156                        breakpoint.as_ref().clone(),
 7157                        edit_action,
 7158                        cx,
 7159                    );
 7160                }
 7161            }))
 7162            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7163                editor.set_breakpoint_context_menu(
 7164                    row,
 7165                    Some(position),
 7166                    event.down.position,
 7167                    window,
 7168                    cx,
 7169                );
 7170            }))
 7171            .tooltip(move |window, cx| {
 7172                Tooltip::with_meta_in(primary_text.clone(), None, meta, &focus_handle, window, cx)
 7173            })
 7174    }
 7175
 7176    fn build_tasks_context(
 7177        project: &Entity<Project>,
 7178        buffer: &Entity<Buffer>,
 7179        buffer_row: u32,
 7180        tasks: &Arc<RunnableTasks>,
 7181        cx: &mut Context<Self>,
 7182    ) -> Task<Option<task::TaskContext>> {
 7183        let position = Point::new(buffer_row, tasks.column);
 7184        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7185        let location = Location {
 7186            buffer: buffer.clone(),
 7187            range: range_start..range_start,
 7188        };
 7189        // Fill in the environmental variables from the tree-sitter captures
 7190        let mut captured_task_variables = TaskVariables::default();
 7191        for (capture_name, value) in tasks.extra_variables.clone() {
 7192            captured_task_variables.insert(
 7193                task::VariableName::Custom(capture_name.into()),
 7194                value.clone(),
 7195            );
 7196        }
 7197        project.update(cx, |project, cx| {
 7198            project.task_store().update(cx, |task_store, cx| {
 7199                task_store.task_context_for_location(captured_task_variables, location, cx)
 7200            })
 7201        })
 7202    }
 7203
 7204    pub fn spawn_nearest_task(
 7205        &mut self,
 7206        action: &SpawnNearestTask,
 7207        window: &mut Window,
 7208        cx: &mut Context<Self>,
 7209    ) {
 7210        let Some((workspace, _)) = self.workspace.clone() else {
 7211            return;
 7212        };
 7213        let Some(project) = self.project.clone() else {
 7214            return;
 7215        };
 7216
 7217        // Try to find a closest, enclosing node using tree-sitter that has a
 7218        // task
 7219        let Some((buffer, buffer_row, tasks)) = self
 7220            .find_enclosing_node_task(cx)
 7221            // Or find the task that's closest in row-distance.
 7222            .or_else(|| self.find_closest_task(cx))
 7223        else {
 7224            return;
 7225        };
 7226
 7227        let reveal_strategy = action.reveal;
 7228        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7229        cx.spawn_in(window, async move |_, cx| {
 7230            let context = task_context.await?;
 7231            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7232
 7233            let resolved = &mut resolved_task.resolved;
 7234            resolved.reveal = reveal_strategy;
 7235
 7236            workspace
 7237                .update_in(cx, |workspace, window, cx| {
 7238                    workspace.schedule_resolved_task(
 7239                        task_source_kind,
 7240                        resolved_task,
 7241                        false,
 7242                        window,
 7243                        cx,
 7244                    );
 7245                })
 7246                .ok()
 7247        })
 7248        .detach();
 7249    }
 7250
 7251    fn find_closest_task(
 7252        &mut self,
 7253        cx: &mut Context<Self>,
 7254    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7255        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7256
 7257        let ((buffer_id, row), tasks) = self
 7258            .tasks
 7259            .iter()
 7260            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7261
 7262        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7263        let tasks = Arc::new(tasks.to_owned());
 7264        Some((buffer, *row, tasks))
 7265    }
 7266
 7267    fn find_enclosing_node_task(
 7268        &mut self,
 7269        cx: &mut Context<Self>,
 7270    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7271        let snapshot = self.buffer.read(cx).snapshot(cx);
 7272        let offset = self.selections.newest::<usize>(cx).head();
 7273        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7274        let buffer_id = excerpt.buffer().remote_id();
 7275
 7276        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7277        let mut cursor = layer.node().walk();
 7278
 7279        while cursor.goto_first_child_for_byte(offset).is_some() {
 7280            if cursor.node().end_byte() == offset {
 7281                cursor.goto_next_sibling();
 7282            }
 7283        }
 7284
 7285        // Ascend to the smallest ancestor that contains the range and has a task.
 7286        loop {
 7287            let node = cursor.node();
 7288            let node_range = node.byte_range();
 7289            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7290
 7291            // Check if this node contains our offset
 7292            if node_range.start <= offset && node_range.end >= offset {
 7293                // If it contains offset, check for task
 7294                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7295                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7296                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7297                }
 7298            }
 7299
 7300            if !cursor.goto_parent() {
 7301                break;
 7302            }
 7303        }
 7304        None
 7305    }
 7306
 7307    fn render_run_indicator(
 7308        &self,
 7309        _style: &EditorStyle,
 7310        is_active: bool,
 7311        row: DisplayRow,
 7312        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7313        cx: &mut Context<Self>,
 7314    ) -> IconButton {
 7315        let color = Color::Muted;
 7316        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7317
 7318        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7319            .shape(ui::IconButtonShape::Square)
 7320            .icon_size(IconSize::XSmall)
 7321            .icon_color(color)
 7322            .toggle_state(is_active)
 7323            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7324                let quick_launch = e.down.button == MouseButton::Left;
 7325                window.focus(&editor.focus_handle(cx));
 7326                editor.toggle_code_actions(
 7327                    &ToggleCodeActions {
 7328                        deployed_from_indicator: Some(row),
 7329                        quick_launch,
 7330                    },
 7331                    window,
 7332                    cx,
 7333                );
 7334            }))
 7335            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7336                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7337            }))
 7338    }
 7339
 7340    pub fn context_menu_visible(&self) -> bool {
 7341        !self.edit_prediction_preview_is_active()
 7342            && self
 7343                .context_menu
 7344                .borrow()
 7345                .as_ref()
 7346                .map_or(false, |menu| menu.visible())
 7347    }
 7348
 7349    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7350        self.context_menu
 7351            .borrow()
 7352            .as_ref()
 7353            .map(|menu| menu.origin())
 7354    }
 7355
 7356    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7357        self.context_menu_options = Some(options);
 7358    }
 7359
 7360    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7361    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7362
 7363    fn render_edit_prediction_popover(
 7364        &mut self,
 7365        text_bounds: &Bounds<Pixels>,
 7366        content_origin: gpui::Point<Pixels>,
 7367        right_margin: Pixels,
 7368        editor_snapshot: &EditorSnapshot,
 7369        visible_row_range: Range<DisplayRow>,
 7370        scroll_top: f32,
 7371        scroll_bottom: f32,
 7372        line_layouts: &[LineWithInvisibles],
 7373        line_height: Pixels,
 7374        scroll_pixel_position: gpui::Point<Pixels>,
 7375        newest_selection_head: Option<DisplayPoint>,
 7376        editor_width: Pixels,
 7377        style: &EditorStyle,
 7378        window: &mut Window,
 7379        cx: &mut App,
 7380    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7381        if self.mode().is_minimap() {
 7382            return None;
 7383        }
 7384        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7385
 7386        if self.edit_prediction_visible_in_cursor_popover(true) {
 7387            return None;
 7388        }
 7389
 7390        match &active_inline_completion.completion {
 7391            InlineCompletion::Move { target, .. } => {
 7392                let target_display_point = target.to_display_point(editor_snapshot);
 7393
 7394                if self.edit_prediction_requires_modifier() {
 7395                    if !self.edit_prediction_preview_is_active() {
 7396                        return None;
 7397                    }
 7398
 7399                    self.render_edit_prediction_modifier_jump_popover(
 7400                        text_bounds,
 7401                        content_origin,
 7402                        visible_row_range,
 7403                        line_layouts,
 7404                        line_height,
 7405                        scroll_pixel_position,
 7406                        newest_selection_head,
 7407                        target_display_point,
 7408                        window,
 7409                        cx,
 7410                    )
 7411                } else {
 7412                    self.render_edit_prediction_eager_jump_popover(
 7413                        text_bounds,
 7414                        content_origin,
 7415                        editor_snapshot,
 7416                        visible_row_range,
 7417                        scroll_top,
 7418                        scroll_bottom,
 7419                        line_height,
 7420                        scroll_pixel_position,
 7421                        target_display_point,
 7422                        editor_width,
 7423                        window,
 7424                        cx,
 7425                    )
 7426                }
 7427            }
 7428            InlineCompletion::Edit {
 7429                display_mode: EditDisplayMode::Inline,
 7430                ..
 7431            } => None,
 7432            InlineCompletion::Edit {
 7433                display_mode: EditDisplayMode::TabAccept,
 7434                edits,
 7435                ..
 7436            } => {
 7437                let range = &edits.first()?.0;
 7438                let target_display_point = range.end.to_display_point(editor_snapshot);
 7439
 7440                self.render_edit_prediction_end_of_line_popover(
 7441                    "Accept",
 7442                    editor_snapshot,
 7443                    visible_row_range,
 7444                    target_display_point,
 7445                    line_height,
 7446                    scroll_pixel_position,
 7447                    content_origin,
 7448                    editor_width,
 7449                    window,
 7450                    cx,
 7451                )
 7452            }
 7453            InlineCompletion::Edit {
 7454                edits,
 7455                edit_preview,
 7456                display_mode: EditDisplayMode::DiffPopover,
 7457                snapshot,
 7458            } => self.render_edit_prediction_diff_popover(
 7459                text_bounds,
 7460                content_origin,
 7461                right_margin,
 7462                editor_snapshot,
 7463                visible_row_range,
 7464                line_layouts,
 7465                line_height,
 7466                scroll_pixel_position,
 7467                newest_selection_head,
 7468                editor_width,
 7469                style,
 7470                edits,
 7471                edit_preview,
 7472                snapshot,
 7473                window,
 7474                cx,
 7475            ),
 7476        }
 7477    }
 7478
 7479    fn render_edit_prediction_modifier_jump_popover(
 7480        &mut self,
 7481        text_bounds: &Bounds<Pixels>,
 7482        content_origin: gpui::Point<Pixels>,
 7483        visible_row_range: Range<DisplayRow>,
 7484        line_layouts: &[LineWithInvisibles],
 7485        line_height: Pixels,
 7486        scroll_pixel_position: gpui::Point<Pixels>,
 7487        newest_selection_head: Option<DisplayPoint>,
 7488        target_display_point: DisplayPoint,
 7489        window: &mut Window,
 7490        cx: &mut App,
 7491    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7492        let scrolled_content_origin =
 7493            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7494
 7495        const SCROLL_PADDING_Y: Pixels = px(12.);
 7496
 7497        if target_display_point.row() < visible_row_range.start {
 7498            return self.render_edit_prediction_scroll_popover(
 7499                |_| SCROLL_PADDING_Y,
 7500                IconName::ArrowUp,
 7501                visible_row_range,
 7502                line_layouts,
 7503                newest_selection_head,
 7504                scrolled_content_origin,
 7505                window,
 7506                cx,
 7507            );
 7508        } else if target_display_point.row() >= visible_row_range.end {
 7509            return self.render_edit_prediction_scroll_popover(
 7510                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7511                IconName::ArrowDown,
 7512                visible_row_range,
 7513                line_layouts,
 7514                newest_selection_head,
 7515                scrolled_content_origin,
 7516                window,
 7517                cx,
 7518            );
 7519        }
 7520
 7521        const POLE_WIDTH: Pixels = px(2.);
 7522
 7523        let line_layout =
 7524            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7525        let target_column = target_display_point.column() as usize;
 7526
 7527        let target_x = line_layout.x_for_index(target_column);
 7528        let target_y =
 7529            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7530
 7531        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7532
 7533        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7534        border_color.l += 0.001;
 7535
 7536        let mut element = v_flex()
 7537            .items_end()
 7538            .when(flag_on_right, |el| el.items_start())
 7539            .child(if flag_on_right {
 7540                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7541                    .rounded_bl(px(0.))
 7542                    .rounded_tl(px(0.))
 7543                    .border_l_2()
 7544                    .border_color(border_color)
 7545            } else {
 7546                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7547                    .rounded_br(px(0.))
 7548                    .rounded_tr(px(0.))
 7549                    .border_r_2()
 7550                    .border_color(border_color)
 7551            })
 7552            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7553            .into_any();
 7554
 7555        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7556
 7557        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7558            - point(
 7559                if flag_on_right {
 7560                    POLE_WIDTH
 7561                } else {
 7562                    size.width - POLE_WIDTH
 7563                },
 7564                size.height - line_height,
 7565            );
 7566
 7567        origin.x = origin.x.max(content_origin.x);
 7568
 7569        element.prepaint_at(origin, window, cx);
 7570
 7571        Some((element, origin))
 7572    }
 7573
 7574    fn render_edit_prediction_scroll_popover(
 7575        &mut self,
 7576        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7577        scroll_icon: IconName,
 7578        visible_row_range: Range<DisplayRow>,
 7579        line_layouts: &[LineWithInvisibles],
 7580        newest_selection_head: Option<DisplayPoint>,
 7581        scrolled_content_origin: gpui::Point<Pixels>,
 7582        window: &mut Window,
 7583        cx: &mut App,
 7584    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7585        let mut element = self
 7586            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7587            .into_any();
 7588
 7589        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7590
 7591        let cursor = newest_selection_head?;
 7592        let cursor_row_layout =
 7593            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7594        let cursor_column = cursor.column() as usize;
 7595
 7596        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7597
 7598        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7599
 7600        element.prepaint_at(origin, window, cx);
 7601        Some((element, origin))
 7602    }
 7603
 7604    fn render_edit_prediction_eager_jump_popover(
 7605        &mut self,
 7606        text_bounds: &Bounds<Pixels>,
 7607        content_origin: gpui::Point<Pixels>,
 7608        editor_snapshot: &EditorSnapshot,
 7609        visible_row_range: Range<DisplayRow>,
 7610        scroll_top: f32,
 7611        scroll_bottom: f32,
 7612        line_height: Pixels,
 7613        scroll_pixel_position: gpui::Point<Pixels>,
 7614        target_display_point: DisplayPoint,
 7615        editor_width: Pixels,
 7616        window: &mut Window,
 7617        cx: &mut App,
 7618    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7619        if target_display_point.row().as_f32() < scroll_top {
 7620            let mut element = self
 7621                .render_edit_prediction_line_popover(
 7622                    "Jump to Edit",
 7623                    Some(IconName::ArrowUp),
 7624                    window,
 7625                    cx,
 7626                )?
 7627                .into_any();
 7628
 7629            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7630            let offset = point(
 7631                (text_bounds.size.width - size.width) / 2.,
 7632                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7633            );
 7634
 7635            let origin = text_bounds.origin + offset;
 7636            element.prepaint_at(origin, window, cx);
 7637            Some((element, origin))
 7638        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7639            let mut element = self
 7640                .render_edit_prediction_line_popover(
 7641                    "Jump to Edit",
 7642                    Some(IconName::ArrowDown),
 7643                    window,
 7644                    cx,
 7645                )?
 7646                .into_any();
 7647
 7648            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7649            let offset = point(
 7650                (text_bounds.size.width - size.width) / 2.,
 7651                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7652            );
 7653
 7654            let origin = text_bounds.origin + offset;
 7655            element.prepaint_at(origin, window, cx);
 7656            Some((element, origin))
 7657        } else {
 7658            self.render_edit_prediction_end_of_line_popover(
 7659                "Jump to Edit",
 7660                editor_snapshot,
 7661                visible_row_range,
 7662                target_display_point,
 7663                line_height,
 7664                scroll_pixel_position,
 7665                content_origin,
 7666                editor_width,
 7667                window,
 7668                cx,
 7669            )
 7670        }
 7671    }
 7672
 7673    fn render_edit_prediction_end_of_line_popover(
 7674        self: &mut Editor,
 7675        label: &'static str,
 7676        editor_snapshot: &EditorSnapshot,
 7677        visible_row_range: Range<DisplayRow>,
 7678        target_display_point: DisplayPoint,
 7679        line_height: Pixels,
 7680        scroll_pixel_position: gpui::Point<Pixels>,
 7681        content_origin: gpui::Point<Pixels>,
 7682        editor_width: Pixels,
 7683        window: &mut Window,
 7684        cx: &mut App,
 7685    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7686        let target_line_end = DisplayPoint::new(
 7687            target_display_point.row(),
 7688            editor_snapshot.line_len(target_display_point.row()),
 7689        );
 7690
 7691        let mut element = self
 7692            .render_edit_prediction_line_popover(label, None, window, cx)?
 7693            .into_any();
 7694
 7695        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7696
 7697        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7698
 7699        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7700        let mut origin = start_point
 7701            + line_origin
 7702            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7703        origin.x = origin.x.max(content_origin.x);
 7704
 7705        let max_x = content_origin.x + editor_width - size.width;
 7706
 7707        if origin.x > max_x {
 7708            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7709
 7710            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7711                origin.y += offset;
 7712                IconName::ArrowUp
 7713            } else {
 7714                origin.y -= offset;
 7715                IconName::ArrowDown
 7716            };
 7717
 7718            element = self
 7719                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7720                .into_any();
 7721
 7722            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7723
 7724            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7725        }
 7726
 7727        element.prepaint_at(origin, window, cx);
 7728        Some((element, origin))
 7729    }
 7730
 7731    fn render_edit_prediction_diff_popover(
 7732        self: &Editor,
 7733        text_bounds: &Bounds<Pixels>,
 7734        content_origin: gpui::Point<Pixels>,
 7735        right_margin: Pixels,
 7736        editor_snapshot: &EditorSnapshot,
 7737        visible_row_range: Range<DisplayRow>,
 7738        line_layouts: &[LineWithInvisibles],
 7739        line_height: Pixels,
 7740        scroll_pixel_position: gpui::Point<Pixels>,
 7741        newest_selection_head: Option<DisplayPoint>,
 7742        editor_width: Pixels,
 7743        style: &EditorStyle,
 7744        edits: &Vec<(Range<Anchor>, String)>,
 7745        edit_preview: &Option<language::EditPreview>,
 7746        snapshot: &language::BufferSnapshot,
 7747        window: &mut Window,
 7748        cx: &mut App,
 7749    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7750        let edit_start = edits
 7751            .first()
 7752            .unwrap()
 7753            .0
 7754            .start
 7755            .to_display_point(editor_snapshot);
 7756        let edit_end = edits
 7757            .last()
 7758            .unwrap()
 7759            .0
 7760            .end
 7761            .to_display_point(editor_snapshot);
 7762
 7763        let is_visible = visible_row_range.contains(&edit_start.row())
 7764            || visible_row_range.contains(&edit_end.row());
 7765        if !is_visible {
 7766            return None;
 7767        }
 7768
 7769        let highlighted_edits =
 7770            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7771
 7772        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7773        let line_count = highlighted_edits.text.lines().count();
 7774
 7775        const BORDER_WIDTH: Pixels = px(1.);
 7776
 7777        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7778        let has_keybind = keybind.is_some();
 7779
 7780        let mut element = h_flex()
 7781            .items_start()
 7782            .child(
 7783                h_flex()
 7784                    .bg(cx.theme().colors().editor_background)
 7785                    .border(BORDER_WIDTH)
 7786                    .shadow_sm()
 7787                    .border_color(cx.theme().colors().border)
 7788                    .rounded_l_lg()
 7789                    .when(line_count > 1, |el| el.rounded_br_lg())
 7790                    .pr_1()
 7791                    .child(styled_text),
 7792            )
 7793            .child(
 7794                h_flex()
 7795                    .h(line_height + BORDER_WIDTH * 2.)
 7796                    .px_1p5()
 7797                    .gap_1()
 7798                    // Workaround: For some reason, there's a gap if we don't do this
 7799                    .ml(-BORDER_WIDTH)
 7800                    .shadow(smallvec![gpui::BoxShadow {
 7801                        color: gpui::black().opacity(0.05),
 7802                        offset: point(px(1.), px(1.)),
 7803                        blur_radius: px(2.),
 7804                        spread_radius: px(0.),
 7805                    }])
 7806                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7807                    .border(BORDER_WIDTH)
 7808                    .border_color(cx.theme().colors().border)
 7809                    .rounded_r_lg()
 7810                    .id("edit_prediction_diff_popover_keybind")
 7811                    .when(!has_keybind, |el| {
 7812                        let status_colors = cx.theme().status();
 7813
 7814                        el.bg(status_colors.error_background)
 7815                            .border_color(status_colors.error.opacity(0.6))
 7816                            .child(Icon::new(IconName::Info).color(Color::Error))
 7817                            .cursor_default()
 7818                            .hoverable_tooltip(move |_window, cx| {
 7819                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7820                            })
 7821                    })
 7822                    .children(keybind),
 7823            )
 7824            .into_any();
 7825
 7826        let longest_row =
 7827            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7828        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7829            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7830        } else {
 7831            layout_line(
 7832                longest_row,
 7833                editor_snapshot,
 7834                style,
 7835                editor_width,
 7836                |_| false,
 7837                window,
 7838                cx,
 7839            )
 7840            .width
 7841        };
 7842
 7843        let viewport_bounds =
 7844            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7845                right: -right_margin,
 7846                ..Default::default()
 7847            });
 7848
 7849        let x_after_longest =
 7850            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 7851                - scroll_pixel_position.x;
 7852
 7853        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7854
 7855        // Fully visible if it can be displayed within the window (allow overlapping other
 7856        // panes). However, this is only allowed if the popover starts within text_bounds.
 7857        let can_position_to_the_right = x_after_longest < text_bounds.right()
 7858            && x_after_longest + element_bounds.width < viewport_bounds.right();
 7859
 7860        let mut origin = if can_position_to_the_right {
 7861            point(
 7862                x_after_longest,
 7863                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 7864                    - scroll_pixel_position.y,
 7865            )
 7866        } else {
 7867            let cursor_row = newest_selection_head.map(|head| head.row());
 7868            let above_edit = edit_start
 7869                .row()
 7870                .0
 7871                .checked_sub(line_count as u32)
 7872                .map(DisplayRow);
 7873            let below_edit = Some(edit_end.row() + 1);
 7874            let above_cursor =
 7875                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 7876            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 7877
 7878            // Place the edit popover adjacent to the edit if there is a location
 7879            // available that is onscreen and does not obscure the cursor. Otherwise,
 7880            // place it adjacent to the cursor.
 7881            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 7882                .into_iter()
 7883                .flatten()
 7884                .find(|&start_row| {
 7885                    let end_row = start_row + line_count as u32;
 7886                    visible_row_range.contains(&start_row)
 7887                        && visible_row_range.contains(&end_row)
 7888                        && cursor_row.map_or(true, |cursor_row| {
 7889                            !((start_row..end_row).contains(&cursor_row))
 7890                        })
 7891                })?;
 7892
 7893            content_origin
 7894                + point(
 7895                    -scroll_pixel_position.x,
 7896                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 7897                )
 7898        };
 7899
 7900        origin.x -= BORDER_WIDTH;
 7901
 7902        window.defer_draw(element, origin, 1);
 7903
 7904        // Do not return an element, since it will already be drawn due to defer_draw.
 7905        None
 7906    }
 7907
 7908    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 7909        px(30.)
 7910    }
 7911
 7912    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 7913        if self.read_only(cx) {
 7914            cx.theme().players().read_only()
 7915        } else {
 7916            self.style.as_ref().unwrap().local_player
 7917        }
 7918    }
 7919
 7920    fn render_edit_prediction_accept_keybind(
 7921        &self,
 7922        window: &mut Window,
 7923        cx: &App,
 7924    ) -> Option<AnyElement> {
 7925        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 7926        let accept_keystroke = accept_binding.keystroke()?;
 7927
 7928        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7929
 7930        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 7931            Color::Accent
 7932        } else {
 7933            Color::Muted
 7934        };
 7935
 7936        h_flex()
 7937            .px_0p5()
 7938            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 7939            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7940            .text_size(TextSize::XSmall.rems(cx))
 7941            .child(h_flex().children(ui::render_modifiers(
 7942                &accept_keystroke.modifiers,
 7943                PlatformStyle::platform(),
 7944                Some(modifiers_color),
 7945                Some(IconSize::XSmall.rems().into()),
 7946                true,
 7947            )))
 7948            .when(is_platform_style_mac, |parent| {
 7949                parent.child(accept_keystroke.key.clone())
 7950            })
 7951            .when(!is_platform_style_mac, |parent| {
 7952                parent.child(
 7953                    Key::new(
 7954                        util::capitalize(&accept_keystroke.key),
 7955                        Some(Color::Default),
 7956                    )
 7957                    .size(Some(IconSize::XSmall.rems().into())),
 7958                )
 7959            })
 7960            .into_any()
 7961            .into()
 7962    }
 7963
 7964    fn render_edit_prediction_line_popover(
 7965        &self,
 7966        label: impl Into<SharedString>,
 7967        icon: Option<IconName>,
 7968        window: &mut Window,
 7969        cx: &App,
 7970    ) -> Option<Stateful<Div>> {
 7971        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 7972
 7973        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7974        let has_keybind = keybind.is_some();
 7975
 7976        let result = h_flex()
 7977            .id("ep-line-popover")
 7978            .py_0p5()
 7979            .pl_1()
 7980            .pr(padding_right)
 7981            .gap_1()
 7982            .rounded_md()
 7983            .border_1()
 7984            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7985            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 7986            .shadow_sm()
 7987            .when(!has_keybind, |el| {
 7988                let status_colors = cx.theme().status();
 7989
 7990                el.bg(status_colors.error_background)
 7991                    .border_color(status_colors.error.opacity(0.6))
 7992                    .pl_2()
 7993                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 7994                    .cursor_default()
 7995                    .hoverable_tooltip(move |_window, cx| {
 7996                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7997                    })
 7998            })
 7999            .children(keybind)
 8000            .child(
 8001                Label::new(label)
 8002                    .size(LabelSize::Small)
 8003                    .when(!has_keybind, |el| {
 8004                        el.color(cx.theme().status().error.into()).strikethrough()
 8005                    }),
 8006            )
 8007            .when(!has_keybind, |el| {
 8008                el.child(
 8009                    h_flex().ml_1().child(
 8010                        Icon::new(IconName::Info)
 8011                            .size(IconSize::Small)
 8012                            .color(cx.theme().status().error.into()),
 8013                    ),
 8014                )
 8015            })
 8016            .when_some(icon, |element, icon| {
 8017                element.child(
 8018                    div()
 8019                        .mt(px(1.5))
 8020                        .child(Icon::new(icon).size(IconSize::Small)),
 8021                )
 8022            });
 8023
 8024        Some(result)
 8025    }
 8026
 8027    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8028        let accent_color = cx.theme().colors().text_accent;
 8029        let editor_bg_color = cx.theme().colors().editor_background;
 8030        editor_bg_color.blend(accent_color.opacity(0.1))
 8031    }
 8032
 8033    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8034        let accent_color = cx.theme().colors().text_accent;
 8035        let editor_bg_color = cx.theme().colors().editor_background;
 8036        editor_bg_color.blend(accent_color.opacity(0.6))
 8037    }
 8038
 8039    fn render_edit_prediction_cursor_popover(
 8040        &self,
 8041        min_width: Pixels,
 8042        max_width: Pixels,
 8043        cursor_point: Point,
 8044        style: &EditorStyle,
 8045        accept_keystroke: Option<&gpui::Keystroke>,
 8046        _window: &Window,
 8047        cx: &mut Context<Editor>,
 8048    ) -> Option<AnyElement> {
 8049        let provider = self.edit_prediction_provider.as_ref()?;
 8050
 8051        if provider.provider.needs_terms_acceptance(cx) {
 8052            return Some(
 8053                h_flex()
 8054                    .min_w(min_width)
 8055                    .flex_1()
 8056                    .px_2()
 8057                    .py_1()
 8058                    .gap_3()
 8059                    .elevation_2(cx)
 8060                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8061                    .id("accept-terms")
 8062                    .cursor_pointer()
 8063                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8064                    .on_click(cx.listener(|this, _event, window, cx| {
 8065                        cx.stop_propagation();
 8066                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8067                        window.dispatch_action(
 8068                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8069                            cx,
 8070                        );
 8071                    }))
 8072                    .child(
 8073                        h_flex()
 8074                            .flex_1()
 8075                            .gap_2()
 8076                            .child(Icon::new(IconName::ZedPredict))
 8077                            .child(Label::new("Accept Terms of Service"))
 8078                            .child(div().w_full())
 8079                            .child(
 8080                                Icon::new(IconName::ArrowUpRight)
 8081                                    .color(Color::Muted)
 8082                                    .size(IconSize::Small),
 8083                            )
 8084                            .into_any_element(),
 8085                    )
 8086                    .into_any(),
 8087            );
 8088        }
 8089
 8090        let is_refreshing = provider.provider.is_refreshing(cx);
 8091
 8092        fn pending_completion_container() -> Div {
 8093            h_flex()
 8094                .h_full()
 8095                .flex_1()
 8096                .gap_2()
 8097                .child(Icon::new(IconName::ZedPredict))
 8098        }
 8099
 8100        let completion = match &self.active_inline_completion {
 8101            Some(prediction) => {
 8102                if !self.has_visible_completions_menu() {
 8103                    const RADIUS: Pixels = px(6.);
 8104                    const BORDER_WIDTH: Pixels = px(1.);
 8105
 8106                    return Some(
 8107                        h_flex()
 8108                            .elevation_2(cx)
 8109                            .border(BORDER_WIDTH)
 8110                            .border_color(cx.theme().colors().border)
 8111                            .when(accept_keystroke.is_none(), |el| {
 8112                                el.border_color(cx.theme().status().error)
 8113                            })
 8114                            .rounded(RADIUS)
 8115                            .rounded_tl(px(0.))
 8116                            .overflow_hidden()
 8117                            .child(div().px_1p5().child(match &prediction.completion {
 8118                                InlineCompletion::Move { target, snapshot } => {
 8119                                    use text::ToPoint as _;
 8120                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8121                                    {
 8122                                        Icon::new(IconName::ZedPredictDown)
 8123                                    } else {
 8124                                        Icon::new(IconName::ZedPredictUp)
 8125                                    }
 8126                                }
 8127                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8128                            }))
 8129                            .child(
 8130                                h_flex()
 8131                                    .gap_1()
 8132                                    .py_1()
 8133                                    .px_2()
 8134                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8135                                    .border_l_1()
 8136                                    .border_color(cx.theme().colors().border)
 8137                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8138                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8139                                        el.child(
 8140                                            Label::new("Hold")
 8141                                                .size(LabelSize::Small)
 8142                                                .when(accept_keystroke.is_none(), |el| {
 8143                                                    el.strikethrough()
 8144                                                })
 8145                                                .line_height_style(LineHeightStyle::UiLabel),
 8146                                        )
 8147                                    })
 8148                                    .id("edit_prediction_cursor_popover_keybind")
 8149                                    .when(accept_keystroke.is_none(), |el| {
 8150                                        let status_colors = cx.theme().status();
 8151
 8152                                        el.bg(status_colors.error_background)
 8153                                            .border_color(status_colors.error.opacity(0.6))
 8154                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8155                                            .cursor_default()
 8156                                            .hoverable_tooltip(move |_window, cx| {
 8157                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8158                                                    .into()
 8159                                            })
 8160                                    })
 8161                                    .when_some(
 8162                                        accept_keystroke.as_ref(),
 8163                                        |el, accept_keystroke| {
 8164                                            el.child(h_flex().children(ui::render_modifiers(
 8165                                                &accept_keystroke.modifiers,
 8166                                                PlatformStyle::platform(),
 8167                                                Some(Color::Default),
 8168                                                Some(IconSize::XSmall.rems().into()),
 8169                                                false,
 8170                                            )))
 8171                                        },
 8172                                    ),
 8173                            )
 8174                            .into_any(),
 8175                    );
 8176                }
 8177
 8178                self.render_edit_prediction_cursor_popover_preview(
 8179                    prediction,
 8180                    cursor_point,
 8181                    style,
 8182                    cx,
 8183                )?
 8184            }
 8185
 8186            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8187                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8188                    stale_completion,
 8189                    cursor_point,
 8190                    style,
 8191                    cx,
 8192                )?,
 8193
 8194                None => {
 8195                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8196                }
 8197            },
 8198
 8199            None => pending_completion_container().child(Label::new("No Prediction")),
 8200        };
 8201
 8202        let completion = if is_refreshing {
 8203            completion
 8204                .with_animation(
 8205                    "loading-completion",
 8206                    Animation::new(Duration::from_secs(2))
 8207                        .repeat()
 8208                        .with_easing(pulsating_between(0.4, 0.8)),
 8209                    |label, delta| label.opacity(delta),
 8210                )
 8211                .into_any_element()
 8212        } else {
 8213            completion.into_any_element()
 8214        };
 8215
 8216        let has_completion = self.active_inline_completion.is_some();
 8217
 8218        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8219        Some(
 8220            h_flex()
 8221                .min_w(min_width)
 8222                .max_w(max_width)
 8223                .flex_1()
 8224                .elevation_2(cx)
 8225                .border_color(cx.theme().colors().border)
 8226                .child(
 8227                    div()
 8228                        .flex_1()
 8229                        .py_1()
 8230                        .px_2()
 8231                        .overflow_hidden()
 8232                        .child(completion),
 8233                )
 8234                .when_some(accept_keystroke, |el, accept_keystroke| {
 8235                    if !accept_keystroke.modifiers.modified() {
 8236                        return el;
 8237                    }
 8238
 8239                    el.child(
 8240                        h_flex()
 8241                            .h_full()
 8242                            .border_l_1()
 8243                            .rounded_r_lg()
 8244                            .border_color(cx.theme().colors().border)
 8245                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8246                            .gap_1()
 8247                            .py_1()
 8248                            .px_2()
 8249                            .child(
 8250                                h_flex()
 8251                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8252                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8253                                    .child(h_flex().children(ui::render_modifiers(
 8254                                        &accept_keystroke.modifiers,
 8255                                        PlatformStyle::platform(),
 8256                                        Some(if !has_completion {
 8257                                            Color::Muted
 8258                                        } else {
 8259                                            Color::Default
 8260                                        }),
 8261                                        None,
 8262                                        false,
 8263                                    ))),
 8264                            )
 8265                            .child(Label::new("Preview").into_any_element())
 8266                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8267                    )
 8268                })
 8269                .into_any(),
 8270        )
 8271    }
 8272
 8273    fn render_edit_prediction_cursor_popover_preview(
 8274        &self,
 8275        completion: &InlineCompletionState,
 8276        cursor_point: Point,
 8277        style: &EditorStyle,
 8278        cx: &mut Context<Editor>,
 8279    ) -> Option<Div> {
 8280        use text::ToPoint as _;
 8281
 8282        fn render_relative_row_jump(
 8283            prefix: impl Into<String>,
 8284            current_row: u32,
 8285            target_row: u32,
 8286        ) -> Div {
 8287            let (row_diff, arrow) = if target_row < current_row {
 8288                (current_row - target_row, IconName::ArrowUp)
 8289            } else {
 8290                (target_row - current_row, IconName::ArrowDown)
 8291            };
 8292
 8293            h_flex()
 8294                .child(
 8295                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8296                        .color(Color::Muted)
 8297                        .size(LabelSize::Small),
 8298                )
 8299                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8300        }
 8301
 8302        match &completion.completion {
 8303            InlineCompletion::Move {
 8304                target, snapshot, ..
 8305            } => Some(
 8306                h_flex()
 8307                    .px_2()
 8308                    .gap_2()
 8309                    .flex_1()
 8310                    .child(
 8311                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8312                            Icon::new(IconName::ZedPredictDown)
 8313                        } else {
 8314                            Icon::new(IconName::ZedPredictUp)
 8315                        },
 8316                    )
 8317                    .child(Label::new("Jump to Edit")),
 8318            ),
 8319
 8320            InlineCompletion::Edit {
 8321                edits,
 8322                edit_preview,
 8323                snapshot,
 8324                display_mode: _,
 8325            } => {
 8326                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8327
 8328                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8329                    &snapshot,
 8330                    &edits,
 8331                    edit_preview.as_ref()?,
 8332                    true,
 8333                    cx,
 8334                )
 8335                .first_line_preview();
 8336
 8337                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8338                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8339
 8340                let preview = h_flex()
 8341                    .gap_1()
 8342                    .min_w_16()
 8343                    .child(styled_text)
 8344                    .when(has_more_lines, |parent| parent.child(""));
 8345
 8346                let left = if first_edit_row != cursor_point.row {
 8347                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8348                        .into_any_element()
 8349                } else {
 8350                    Icon::new(IconName::ZedPredict).into_any_element()
 8351                };
 8352
 8353                Some(
 8354                    h_flex()
 8355                        .h_full()
 8356                        .flex_1()
 8357                        .gap_2()
 8358                        .pr_1()
 8359                        .overflow_x_hidden()
 8360                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8361                        .child(left)
 8362                        .child(preview),
 8363                )
 8364            }
 8365        }
 8366    }
 8367
 8368    fn render_context_menu(
 8369        &self,
 8370        style: &EditorStyle,
 8371        max_height_in_lines: u32,
 8372        window: &mut Window,
 8373        cx: &mut Context<Editor>,
 8374    ) -> Option<AnyElement> {
 8375        let menu = self.context_menu.borrow();
 8376        let menu = menu.as_ref()?;
 8377        if !menu.visible() {
 8378            return None;
 8379        };
 8380        Some(menu.render(style, max_height_in_lines, window, cx))
 8381    }
 8382
 8383    fn render_context_menu_aside(
 8384        &mut self,
 8385        max_size: Size<Pixels>,
 8386        window: &mut Window,
 8387        cx: &mut Context<Editor>,
 8388    ) -> Option<AnyElement> {
 8389        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8390            if menu.visible() {
 8391                menu.render_aside(self, max_size, window, cx)
 8392            } else {
 8393                None
 8394            }
 8395        })
 8396    }
 8397
 8398    fn hide_context_menu(
 8399        &mut self,
 8400        window: &mut Window,
 8401        cx: &mut Context<Self>,
 8402    ) -> Option<CodeContextMenu> {
 8403        cx.notify();
 8404        self.completion_tasks.clear();
 8405        let context_menu = self.context_menu.borrow_mut().take();
 8406        self.stale_inline_completion_in_menu.take();
 8407        self.update_visible_inline_completion(window, cx);
 8408        context_menu
 8409    }
 8410
 8411    fn show_snippet_choices(
 8412        &mut self,
 8413        choices: &Vec<String>,
 8414        selection: Range<Anchor>,
 8415        cx: &mut Context<Self>,
 8416    ) {
 8417        if selection.start.buffer_id.is_none() {
 8418            return;
 8419        }
 8420        let buffer_id = selection.start.buffer_id.unwrap();
 8421        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8422        let id = post_inc(&mut self.next_completion_id);
 8423        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8424
 8425        if let Some(buffer) = buffer {
 8426            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8427                CompletionsMenu::new_snippet_choices(
 8428                    id,
 8429                    true,
 8430                    choices,
 8431                    selection,
 8432                    buffer,
 8433                    snippet_sort_order,
 8434                ),
 8435            ));
 8436        }
 8437    }
 8438
 8439    pub fn insert_snippet(
 8440        &mut self,
 8441        insertion_ranges: &[Range<usize>],
 8442        snippet: Snippet,
 8443        window: &mut Window,
 8444        cx: &mut Context<Self>,
 8445    ) -> Result<()> {
 8446        struct Tabstop<T> {
 8447            is_end_tabstop: bool,
 8448            ranges: Vec<Range<T>>,
 8449            choices: Option<Vec<String>>,
 8450        }
 8451
 8452        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8453            let snippet_text: Arc<str> = snippet.text.clone().into();
 8454            let edits = insertion_ranges
 8455                .iter()
 8456                .cloned()
 8457                .map(|range| (range, snippet_text.clone()));
 8458            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8459
 8460            let snapshot = &*buffer.read(cx);
 8461            let snippet = &snippet;
 8462            snippet
 8463                .tabstops
 8464                .iter()
 8465                .map(|tabstop| {
 8466                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8467                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8468                    });
 8469                    let mut tabstop_ranges = tabstop
 8470                        .ranges
 8471                        .iter()
 8472                        .flat_map(|tabstop_range| {
 8473                            let mut delta = 0_isize;
 8474                            insertion_ranges.iter().map(move |insertion_range| {
 8475                                let insertion_start = insertion_range.start as isize + delta;
 8476                                delta +=
 8477                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8478
 8479                                let start = ((insertion_start + tabstop_range.start) as usize)
 8480                                    .min(snapshot.len());
 8481                                let end = ((insertion_start + tabstop_range.end) as usize)
 8482                                    .min(snapshot.len());
 8483                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8484                            })
 8485                        })
 8486                        .collect::<Vec<_>>();
 8487                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8488
 8489                    Tabstop {
 8490                        is_end_tabstop,
 8491                        ranges: tabstop_ranges,
 8492                        choices: tabstop.choices.clone(),
 8493                    }
 8494                })
 8495                .collect::<Vec<_>>()
 8496        });
 8497        if let Some(tabstop) = tabstops.first() {
 8498            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8499                s.select_ranges(tabstop.ranges.iter().cloned());
 8500            });
 8501
 8502            if let Some(choices) = &tabstop.choices {
 8503                if let Some(selection) = tabstop.ranges.first() {
 8504                    self.show_snippet_choices(choices, selection.clone(), cx)
 8505                }
 8506            }
 8507
 8508            // If we're already at the last tabstop and it's at the end of the snippet,
 8509            // we're done, we don't need to keep the state around.
 8510            if !tabstop.is_end_tabstop {
 8511                let choices = tabstops
 8512                    .iter()
 8513                    .map(|tabstop| tabstop.choices.clone())
 8514                    .collect();
 8515
 8516                let ranges = tabstops
 8517                    .into_iter()
 8518                    .map(|tabstop| tabstop.ranges)
 8519                    .collect::<Vec<_>>();
 8520
 8521                self.snippet_stack.push(SnippetState {
 8522                    active_index: 0,
 8523                    ranges,
 8524                    choices,
 8525                });
 8526            }
 8527
 8528            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8529            if self.autoclose_regions.is_empty() {
 8530                let snapshot = self.buffer.read(cx).snapshot(cx);
 8531                for selection in &mut self.selections.all::<Point>(cx) {
 8532                    let selection_head = selection.head();
 8533                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8534                        continue;
 8535                    };
 8536
 8537                    let mut bracket_pair = None;
 8538                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8539                    let prev_chars = snapshot
 8540                        .reversed_chars_at(selection_head)
 8541                        .collect::<String>();
 8542                    for (pair, enabled) in scope.brackets() {
 8543                        if enabled
 8544                            && pair.close
 8545                            && prev_chars.starts_with(pair.start.as_str())
 8546                            && next_chars.starts_with(pair.end.as_str())
 8547                        {
 8548                            bracket_pair = Some(pair.clone());
 8549                            break;
 8550                        }
 8551                    }
 8552                    if let Some(pair) = bracket_pair {
 8553                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8554                        let autoclose_enabled =
 8555                            self.use_autoclose && snapshot_settings.use_autoclose;
 8556                        if autoclose_enabled {
 8557                            let start = snapshot.anchor_after(selection_head);
 8558                            let end = snapshot.anchor_after(selection_head);
 8559                            self.autoclose_regions.push(AutocloseRegion {
 8560                                selection_id: selection.id,
 8561                                range: start..end,
 8562                                pair,
 8563                            });
 8564                        }
 8565                    }
 8566                }
 8567            }
 8568        }
 8569        Ok(())
 8570    }
 8571
 8572    pub fn move_to_next_snippet_tabstop(
 8573        &mut self,
 8574        window: &mut Window,
 8575        cx: &mut Context<Self>,
 8576    ) -> bool {
 8577        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8578    }
 8579
 8580    pub fn move_to_prev_snippet_tabstop(
 8581        &mut self,
 8582        window: &mut Window,
 8583        cx: &mut Context<Self>,
 8584    ) -> bool {
 8585        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8586    }
 8587
 8588    pub fn move_to_snippet_tabstop(
 8589        &mut self,
 8590        bias: Bias,
 8591        window: &mut Window,
 8592        cx: &mut Context<Self>,
 8593    ) -> bool {
 8594        if let Some(mut snippet) = self.snippet_stack.pop() {
 8595            match bias {
 8596                Bias::Left => {
 8597                    if snippet.active_index > 0 {
 8598                        snippet.active_index -= 1;
 8599                    } else {
 8600                        self.snippet_stack.push(snippet);
 8601                        return false;
 8602                    }
 8603                }
 8604                Bias::Right => {
 8605                    if snippet.active_index + 1 < snippet.ranges.len() {
 8606                        snippet.active_index += 1;
 8607                    } else {
 8608                        self.snippet_stack.push(snippet);
 8609                        return false;
 8610                    }
 8611                }
 8612            }
 8613            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8614                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8615                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8616                });
 8617
 8618                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8619                    if let Some(selection) = current_ranges.first() {
 8620                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8621                    }
 8622                }
 8623
 8624                // If snippet state is not at the last tabstop, push it back on the stack
 8625                if snippet.active_index + 1 < snippet.ranges.len() {
 8626                    self.snippet_stack.push(snippet);
 8627                }
 8628                return true;
 8629            }
 8630        }
 8631
 8632        false
 8633    }
 8634
 8635    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8636        self.transact(window, cx, |this, window, cx| {
 8637            this.select_all(&SelectAll, window, cx);
 8638            this.insert("", window, cx);
 8639        });
 8640    }
 8641
 8642    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8643        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8644        self.transact(window, cx, |this, window, cx| {
 8645            this.select_autoclose_pair(window, cx);
 8646            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8647            if !this.linked_edit_ranges.is_empty() {
 8648                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8649                let snapshot = this.buffer.read(cx).snapshot(cx);
 8650
 8651                for selection in selections.iter() {
 8652                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8653                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8654                    if selection_start.buffer_id != selection_end.buffer_id {
 8655                        continue;
 8656                    }
 8657                    if let Some(ranges) =
 8658                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8659                    {
 8660                        for (buffer, entries) in ranges {
 8661                            linked_ranges.entry(buffer).or_default().extend(entries);
 8662                        }
 8663                    }
 8664                }
 8665            }
 8666
 8667            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8668            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8669            for selection in &mut selections {
 8670                if selection.is_empty() {
 8671                    let old_head = selection.head();
 8672                    let mut new_head =
 8673                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8674                            .to_point(&display_map);
 8675                    if let Some((buffer, line_buffer_range)) = display_map
 8676                        .buffer_snapshot
 8677                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8678                    {
 8679                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8680                        let indent_len = match indent_size.kind {
 8681                            IndentKind::Space => {
 8682                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8683                            }
 8684                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8685                        };
 8686                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8687                            let indent_len = indent_len.get();
 8688                            new_head = cmp::min(
 8689                                new_head,
 8690                                MultiBufferPoint::new(
 8691                                    old_head.row,
 8692                                    ((old_head.column - 1) / indent_len) * indent_len,
 8693                                ),
 8694                            );
 8695                        }
 8696                    }
 8697
 8698                    selection.set_head(new_head, SelectionGoal::None);
 8699                }
 8700            }
 8701
 8702            this.signature_help_state.set_backspace_pressed(true);
 8703            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8704                s.select(selections)
 8705            });
 8706            this.insert("", window, cx);
 8707            let empty_str: Arc<str> = Arc::from("");
 8708            for (buffer, edits) in linked_ranges {
 8709                let snapshot = buffer.read(cx).snapshot();
 8710                use text::ToPoint as TP;
 8711
 8712                let edits = edits
 8713                    .into_iter()
 8714                    .map(|range| {
 8715                        let end_point = TP::to_point(&range.end, &snapshot);
 8716                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8717
 8718                        if end_point == start_point {
 8719                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8720                                .saturating_sub(1);
 8721                            start_point =
 8722                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8723                        };
 8724
 8725                        (start_point..end_point, empty_str.clone())
 8726                    })
 8727                    .sorted_by_key(|(range, _)| range.start)
 8728                    .collect::<Vec<_>>();
 8729                buffer.update(cx, |this, cx| {
 8730                    this.edit(edits, None, cx);
 8731                })
 8732            }
 8733            this.refresh_inline_completion(true, false, window, cx);
 8734            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8735        });
 8736    }
 8737
 8738    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8739        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8740        self.transact(window, cx, |this, window, cx| {
 8741            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8742                s.move_with(|map, selection| {
 8743                    if selection.is_empty() {
 8744                        let cursor = movement::right(map, selection.head());
 8745                        selection.end = cursor;
 8746                        selection.reversed = true;
 8747                        selection.goal = SelectionGoal::None;
 8748                    }
 8749                })
 8750            });
 8751            this.insert("", window, cx);
 8752            this.refresh_inline_completion(true, false, window, cx);
 8753        });
 8754    }
 8755
 8756    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8757        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8758        if self.move_to_prev_snippet_tabstop(window, cx) {
 8759            return;
 8760        }
 8761        self.outdent(&Outdent, window, cx);
 8762    }
 8763
 8764    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8765        if self.move_to_next_snippet_tabstop(window, cx) {
 8766            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8767            return;
 8768        }
 8769        if self.read_only(cx) {
 8770            return;
 8771        }
 8772        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8773        let mut selections = self.selections.all_adjusted(cx);
 8774        let buffer = self.buffer.read(cx);
 8775        let snapshot = buffer.snapshot(cx);
 8776        let rows_iter = selections.iter().map(|s| s.head().row);
 8777        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8778
 8779        let has_some_cursor_in_whitespace = selections
 8780            .iter()
 8781            .filter(|selection| selection.is_empty())
 8782            .any(|selection| {
 8783                let cursor = selection.head();
 8784                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8785                cursor.column < current_indent.len
 8786            });
 8787
 8788        let mut edits = Vec::new();
 8789        let mut prev_edited_row = 0;
 8790        let mut row_delta = 0;
 8791        for selection in &mut selections {
 8792            if selection.start.row != prev_edited_row {
 8793                row_delta = 0;
 8794            }
 8795            prev_edited_row = selection.end.row;
 8796
 8797            // If the selection is non-empty, then increase the indentation of the selected lines.
 8798            if !selection.is_empty() {
 8799                row_delta =
 8800                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8801                continue;
 8802            }
 8803
 8804            let cursor = selection.head();
 8805            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8806            if let Some(suggested_indent) =
 8807                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8808            {
 8809                // Don't do anything if already at suggested indent
 8810                // and there is any other cursor which is not
 8811                if has_some_cursor_in_whitespace
 8812                    && cursor.column == current_indent.len
 8813                    && current_indent.len == suggested_indent.len
 8814                {
 8815                    continue;
 8816                }
 8817
 8818                // Adjust line and move cursor to suggested indent
 8819                // if cursor is not at suggested indent
 8820                if cursor.column < suggested_indent.len
 8821                    && cursor.column <= current_indent.len
 8822                    && current_indent.len <= suggested_indent.len
 8823                {
 8824                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8825                    selection.end = selection.start;
 8826                    if row_delta == 0 {
 8827                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8828                            cursor.row,
 8829                            current_indent,
 8830                            suggested_indent,
 8831                        ));
 8832                        row_delta = suggested_indent.len - current_indent.len;
 8833                    }
 8834                    continue;
 8835                }
 8836
 8837                // If current indent is more than suggested indent
 8838                // only move cursor to current indent and skip indent
 8839                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 8840                    selection.start = Point::new(cursor.row, current_indent.len);
 8841                    selection.end = selection.start;
 8842                    continue;
 8843                }
 8844            }
 8845
 8846            // Otherwise, insert a hard or soft tab.
 8847            let settings = buffer.language_settings_at(cursor, cx);
 8848            let tab_size = if settings.hard_tabs {
 8849                IndentSize::tab()
 8850            } else {
 8851                let tab_size = settings.tab_size.get();
 8852                let indent_remainder = snapshot
 8853                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 8854                    .flat_map(str::chars)
 8855                    .fold(row_delta % tab_size, |counter: u32, c| {
 8856                        if c == '\t' {
 8857                            0
 8858                        } else {
 8859                            (counter + 1) % tab_size
 8860                        }
 8861                    });
 8862
 8863                let chars_to_next_tab_stop = tab_size - indent_remainder;
 8864                IndentSize::spaces(chars_to_next_tab_stop)
 8865            };
 8866            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 8867            selection.end = selection.start;
 8868            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 8869            row_delta += tab_size.len;
 8870        }
 8871
 8872        self.transact(window, cx, |this, window, cx| {
 8873            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8874            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8875                s.select(selections)
 8876            });
 8877            this.refresh_inline_completion(true, false, window, cx);
 8878        });
 8879    }
 8880
 8881    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 8882        if self.read_only(cx) {
 8883            return;
 8884        }
 8885        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8886        let mut selections = self.selections.all::<Point>(cx);
 8887        let mut prev_edited_row = 0;
 8888        let mut row_delta = 0;
 8889        let mut edits = Vec::new();
 8890        let buffer = self.buffer.read(cx);
 8891        let snapshot = buffer.snapshot(cx);
 8892        for selection in &mut selections {
 8893            if selection.start.row != prev_edited_row {
 8894                row_delta = 0;
 8895            }
 8896            prev_edited_row = selection.end.row;
 8897
 8898            row_delta =
 8899                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8900        }
 8901
 8902        self.transact(window, cx, |this, window, cx| {
 8903            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8904            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8905                s.select(selections)
 8906            });
 8907        });
 8908    }
 8909
 8910    fn indent_selection(
 8911        buffer: &MultiBuffer,
 8912        snapshot: &MultiBufferSnapshot,
 8913        selection: &mut Selection<Point>,
 8914        edits: &mut Vec<(Range<Point>, String)>,
 8915        delta_for_start_row: u32,
 8916        cx: &App,
 8917    ) -> u32 {
 8918        let settings = buffer.language_settings_at(selection.start, cx);
 8919        let tab_size = settings.tab_size.get();
 8920        let indent_kind = if settings.hard_tabs {
 8921            IndentKind::Tab
 8922        } else {
 8923            IndentKind::Space
 8924        };
 8925        let mut start_row = selection.start.row;
 8926        let mut end_row = selection.end.row + 1;
 8927
 8928        // If a selection ends at the beginning of a line, don't indent
 8929        // that last line.
 8930        if selection.end.column == 0 && selection.end.row > selection.start.row {
 8931            end_row -= 1;
 8932        }
 8933
 8934        // Avoid re-indenting a row that has already been indented by a
 8935        // previous selection, but still update this selection's column
 8936        // to reflect that indentation.
 8937        if delta_for_start_row > 0 {
 8938            start_row += 1;
 8939            selection.start.column += delta_for_start_row;
 8940            if selection.end.row == selection.start.row {
 8941                selection.end.column += delta_for_start_row;
 8942            }
 8943        }
 8944
 8945        let mut delta_for_end_row = 0;
 8946        let has_multiple_rows = start_row + 1 != end_row;
 8947        for row in start_row..end_row {
 8948            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 8949            let indent_delta = match (current_indent.kind, indent_kind) {
 8950                (IndentKind::Space, IndentKind::Space) => {
 8951                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 8952                    IndentSize::spaces(columns_to_next_tab_stop)
 8953                }
 8954                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 8955                (_, IndentKind::Tab) => IndentSize::tab(),
 8956            };
 8957
 8958            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 8959                0
 8960            } else {
 8961                selection.start.column
 8962            };
 8963            let row_start = Point::new(row, start);
 8964            edits.push((
 8965                row_start..row_start,
 8966                indent_delta.chars().collect::<String>(),
 8967            ));
 8968
 8969            // Update this selection's endpoints to reflect the indentation.
 8970            if row == selection.start.row {
 8971                selection.start.column += indent_delta.len;
 8972            }
 8973            if row == selection.end.row {
 8974                selection.end.column += indent_delta.len;
 8975                delta_for_end_row = indent_delta.len;
 8976            }
 8977        }
 8978
 8979        if selection.start.row == selection.end.row {
 8980            delta_for_start_row + delta_for_end_row
 8981        } else {
 8982            delta_for_end_row
 8983        }
 8984    }
 8985
 8986    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 8987        if self.read_only(cx) {
 8988            return;
 8989        }
 8990        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8991        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8992        let selections = self.selections.all::<Point>(cx);
 8993        let mut deletion_ranges = Vec::new();
 8994        let mut last_outdent = None;
 8995        {
 8996            let buffer = self.buffer.read(cx);
 8997            let snapshot = buffer.snapshot(cx);
 8998            for selection in &selections {
 8999                let settings = buffer.language_settings_at(selection.start, cx);
 9000                let tab_size = settings.tab_size.get();
 9001                let mut rows = selection.spanned_rows(false, &display_map);
 9002
 9003                // Avoid re-outdenting a row that has already been outdented by a
 9004                // previous selection.
 9005                if let Some(last_row) = last_outdent {
 9006                    if last_row == rows.start {
 9007                        rows.start = rows.start.next_row();
 9008                    }
 9009                }
 9010                let has_multiple_rows = rows.len() > 1;
 9011                for row in rows.iter_rows() {
 9012                    let indent_size = snapshot.indent_size_for_line(row);
 9013                    if indent_size.len > 0 {
 9014                        let deletion_len = match indent_size.kind {
 9015                            IndentKind::Space => {
 9016                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9017                                if columns_to_prev_tab_stop == 0 {
 9018                                    tab_size
 9019                                } else {
 9020                                    columns_to_prev_tab_stop
 9021                                }
 9022                            }
 9023                            IndentKind::Tab => 1,
 9024                        };
 9025                        let start = if has_multiple_rows
 9026                            || deletion_len > selection.start.column
 9027                            || indent_size.len < selection.start.column
 9028                        {
 9029                            0
 9030                        } else {
 9031                            selection.start.column - deletion_len
 9032                        };
 9033                        deletion_ranges.push(
 9034                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9035                        );
 9036                        last_outdent = Some(row);
 9037                    }
 9038                }
 9039            }
 9040        }
 9041
 9042        self.transact(window, cx, |this, window, cx| {
 9043            this.buffer.update(cx, |buffer, cx| {
 9044                let empty_str: Arc<str> = Arc::default();
 9045                buffer.edit(
 9046                    deletion_ranges
 9047                        .into_iter()
 9048                        .map(|range| (range, empty_str.clone())),
 9049                    None,
 9050                    cx,
 9051                );
 9052            });
 9053            let selections = this.selections.all::<usize>(cx);
 9054            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9055                s.select(selections)
 9056            });
 9057        });
 9058    }
 9059
 9060    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9061        if self.read_only(cx) {
 9062            return;
 9063        }
 9064        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9065        let selections = self
 9066            .selections
 9067            .all::<usize>(cx)
 9068            .into_iter()
 9069            .map(|s| s.range());
 9070
 9071        self.transact(window, cx, |this, window, cx| {
 9072            this.buffer.update(cx, |buffer, cx| {
 9073                buffer.autoindent_ranges(selections, cx);
 9074            });
 9075            let selections = this.selections.all::<usize>(cx);
 9076            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9077                s.select(selections)
 9078            });
 9079        });
 9080    }
 9081
 9082    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9083        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9084        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9085        let selections = self.selections.all::<Point>(cx);
 9086
 9087        let mut new_cursors = Vec::new();
 9088        let mut edit_ranges = Vec::new();
 9089        let mut selections = selections.iter().peekable();
 9090        while let Some(selection) = selections.next() {
 9091            let mut rows = selection.spanned_rows(false, &display_map);
 9092            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9093
 9094            // Accumulate contiguous regions of rows that we want to delete.
 9095            while let Some(next_selection) = selections.peek() {
 9096                let next_rows = next_selection.spanned_rows(false, &display_map);
 9097                if next_rows.start <= rows.end {
 9098                    rows.end = next_rows.end;
 9099                    selections.next().unwrap();
 9100                } else {
 9101                    break;
 9102                }
 9103            }
 9104
 9105            let buffer = &display_map.buffer_snapshot;
 9106            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9107            let edit_end;
 9108            let cursor_buffer_row;
 9109            if buffer.max_point().row >= rows.end.0 {
 9110                // If there's a line after the range, delete the \n from the end of the row range
 9111                // and position the cursor on the next line.
 9112                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9113                cursor_buffer_row = rows.end;
 9114            } else {
 9115                // If there isn't a line after the range, delete the \n from the line before the
 9116                // start of the row range and position the cursor there.
 9117                edit_start = edit_start.saturating_sub(1);
 9118                edit_end = buffer.len();
 9119                cursor_buffer_row = rows.start.previous_row();
 9120            }
 9121
 9122            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9123            *cursor.column_mut() =
 9124                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9125
 9126            new_cursors.push((
 9127                selection.id,
 9128                buffer.anchor_after(cursor.to_point(&display_map)),
 9129            ));
 9130            edit_ranges.push(edit_start..edit_end);
 9131        }
 9132
 9133        self.transact(window, cx, |this, window, cx| {
 9134            let buffer = this.buffer.update(cx, |buffer, cx| {
 9135                let empty_str: Arc<str> = Arc::default();
 9136                buffer.edit(
 9137                    edit_ranges
 9138                        .into_iter()
 9139                        .map(|range| (range, empty_str.clone())),
 9140                    None,
 9141                    cx,
 9142                );
 9143                buffer.snapshot(cx)
 9144            });
 9145            let new_selections = new_cursors
 9146                .into_iter()
 9147                .map(|(id, cursor)| {
 9148                    let cursor = cursor.to_point(&buffer);
 9149                    Selection {
 9150                        id,
 9151                        start: cursor,
 9152                        end: cursor,
 9153                        reversed: false,
 9154                        goal: SelectionGoal::None,
 9155                    }
 9156                })
 9157                .collect();
 9158
 9159            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9160                s.select(new_selections);
 9161            });
 9162        });
 9163    }
 9164
 9165    pub fn join_lines_impl(
 9166        &mut self,
 9167        insert_whitespace: bool,
 9168        window: &mut Window,
 9169        cx: &mut Context<Self>,
 9170    ) {
 9171        if self.read_only(cx) {
 9172            return;
 9173        }
 9174        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9175        for selection in self.selections.all::<Point>(cx) {
 9176            let start = MultiBufferRow(selection.start.row);
 9177            // Treat single line selections as if they include the next line. Otherwise this action
 9178            // would do nothing for single line selections individual cursors.
 9179            let end = if selection.start.row == selection.end.row {
 9180                MultiBufferRow(selection.start.row + 1)
 9181            } else {
 9182                MultiBufferRow(selection.end.row)
 9183            };
 9184
 9185            if let Some(last_row_range) = row_ranges.last_mut() {
 9186                if start <= last_row_range.end {
 9187                    last_row_range.end = end;
 9188                    continue;
 9189                }
 9190            }
 9191            row_ranges.push(start..end);
 9192        }
 9193
 9194        let snapshot = self.buffer.read(cx).snapshot(cx);
 9195        let mut cursor_positions = Vec::new();
 9196        for row_range in &row_ranges {
 9197            let anchor = snapshot.anchor_before(Point::new(
 9198                row_range.end.previous_row().0,
 9199                snapshot.line_len(row_range.end.previous_row()),
 9200            ));
 9201            cursor_positions.push(anchor..anchor);
 9202        }
 9203
 9204        self.transact(window, cx, |this, window, cx| {
 9205            for row_range in row_ranges.into_iter().rev() {
 9206                for row in row_range.iter_rows().rev() {
 9207                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9208                    let next_line_row = row.next_row();
 9209                    let indent = snapshot.indent_size_for_line(next_line_row);
 9210                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9211
 9212                    let replace =
 9213                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9214                            " "
 9215                        } else {
 9216                            ""
 9217                        };
 9218
 9219                    this.buffer.update(cx, |buffer, cx| {
 9220                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9221                    });
 9222                }
 9223            }
 9224
 9225            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9226                s.select_anchor_ranges(cursor_positions)
 9227            });
 9228        });
 9229    }
 9230
 9231    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9232        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9233        self.join_lines_impl(true, window, cx);
 9234    }
 9235
 9236    pub fn sort_lines_case_sensitive(
 9237        &mut self,
 9238        _: &SortLinesCaseSensitive,
 9239        window: &mut Window,
 9240        cx: &mut Context<Self>,
 9241    ) {
 9242        self.manipulate_lines(window, cx, |lines| lines.sort())
 9243    }
 9244
 9245    pub fn sort_lines_case_insensitive(
 9246        &mut self,
 9247        _: &SortLinesCaseInsensitive,
 9248        window: &mut Window,
 9249        cx: &mut Context<Self>,
 9250    ) {
 9251        self.manipulate_lines(window, cx, |lines| {
 9252            lines.sort_by_key(|line| line.to_lowercase())
 9253        })
 9254    }
 9255
 9256    pub fn unique_lines_case_insensitive(
 9257        &mut self,
 9258        _: &UniqueLinesCaseInsensitive,
 9259        window: &mut Window,
 9260        cx: &mut Context<Self>,
 9261    ) {
 9262        self.manipulate_lines(window, cx, |lines| {
 9263            let mut seen = HashSet::default();
 9264            lines.retain(|line| seen.insert(line.to_lowercase()));
 9265        })
 9266    }
 9267
 9268    pub fn unique_lines_case_sensitive(
 9269        &mut self,
 9270        _: &UniqueLinesCaseSensitive,
 9271        window: &mut Window,
 9272        cx: &mut Context<Self>,
 9273    ) {
 9274        self.manipulate_lines(window, cx, |lines| {
 9275            let mut seen = HashSet::default();
 9276            lines.retain(|line| seen.insert(*line));
 9277        })
 9278    }
 9279
 9280    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9281        let Some(project) = self.project.clone() else {
 9282            return;
 9283        };
 9284        self.reload(project, window, cx)
 9285            .detach_and_notify_err(window, cx);
 9286    }
 9287
 9288    pub fn restore_file(
 9289        &mut self,
 9290        _: &::git::RestoreFile,
 9291        window: &mut Window,
 9292        cx: &mut Context<Self>,
 9293    ) {
 9294        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9295        let mut buffer_ids = HashSet::default();
 9296        let snapshot = self.buffer().read(cx).snapshot(cx);
 9297        for selection in self.selections.all::<usize>(cx) {
 9298            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9299        }
 9300
 9301        let buffer = self.buffer().read(cx);
 9302        let ranges = buffer_ids
 9303            .into_iter()
 9304            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9305            .collect::<Vec<_>>();
 9306
 9307        self.restore_hunks_in_ranges(ranges, window, cx);
 9308    }
 9309
 9310    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9311        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9312        let selections = self
 9313            .selections
 9314            .all(cx)
 9315            .into_iter()
 9316            .map(|s| s.range())
 9317            .collect();
 9318        self.restore_hunks_in_ranges(selections, window, cx);
 9319    }
 9320
 9321    pub fn restore_hunks_in_ranges(
 9322        &mut self,
 9323        ranges: Vec<Range<Point>>,
 9324        window: &mut Window,
 9325        cx: &mut Context<Editor>,
 9326    ) {
 9327        let mut revert_changes = HashMap::default();
 9328        let chunk_by = self
 9329            .snapshot(window, cx)
 9330            .hunks_for_ranges(ranges)
 9331            .into_iter()
 9332            .chunk_by(|hunk| hunk.buffer_id);
 9333        for (buffer_id, hunks) in &chunk_by {
 9334            let hunks = hunks.collect::<Vec<_>>();
 9335            for hunk in &hunks {
 9336                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9337            }
 9338            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9339        }
 9340        drop(chunk_by);
 9341        if !revert_changes.is_empty() {
 9342            self.transact(window, cx, |editor, window, cx| {
 9343                editor.restore(revert_changes, window, cx);
 9344            });
 9345        }
 9346    }
 9347
 9348    pub fn open_active_item_in_terminal(
 9349        &mut self,
 9350        _: &OpenInTerminal,
 9351        window: &mut Window,
 9352        cx: &mut Context<Self>,
 9353    ) {
 9354        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9355            let project_path = buffer.read(cx).project_path(cx)?;
 9356            let project = self.project.as_ref()?.read(cx);
 9357            let entry = project.entry_for_path(&project_path, cx)?;
 9358            let parent = match &entry.canonical_path {
 9359                Some(canonical_path) => canonical_path.to_path_buf(),
 9360                None => project.absolute_path(&project_path, cx)?,
 9361            }
 9362            .parent()?
 9363            .to_path_buf();
 9364            Some(parent)
 9365        }) {
 9366            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9367        }
 9368    }
 9369
 9370    fn set_breakpoint_context_menu(
 9371        &mut self,
 9372        display_row: DisplayRow,
 9373        position: Option<Anchor>,
 9374        clicked_point: gpui::Point<Pixels>,
 9375        window: &mut Window,
 9376        cx: &mut Context<Self>,
 9377    ) {
 9378        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9379            return;
 9380        }
 9381        let source = self
 9382            .buffer
 9383            .read(cx)
 9384            .snapshot(cx)
 9385            .anchor_before(Point::new(display_row.0, 0u32));
 9386
 9387        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9388
 9389        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9390            self,
 9391            source,
 9392            clicked_point,
 9393            context_menu,
 9394            window,
 9395            cx,
 9396        );
 9397    }
 9398
 9399    fn add_edit_breakpoint_block(
 9400        &mut self,
 9401        anchor: Anchor,
 9402        breakpoint: &Breakpoint,
 9403        edit_action: BreakpointPromptEditAction,
 9404        window: &mut Window,
 9405        cx: &mut Context<Self>,
 9406    ) {
 9407        let weak_editor = cx.weak_entity();
 9408        let bp_prompt = cx.new(|cx| {
 9409            BreakpointPromptEditor::new(
 9410                weak_editor,
 9411                anchor,
 9412                breakpoint.clone(),
 9413                edit_action,
 9414                window,
 9415                cx,
 9416            )
 9417        });
 9418
 9419        let height = bp_prompt.update(cx, |this, cx| {
 9420            this.prompt
 9421                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9422        });
 9423        let cloned_prompt = bp_prompt.clone();
 9424        let blocks = vec![BlockProperties {
 9425            style: BlockStyle::Sticky,
 9426            placement: BlockPlacement::Above(anchor),
 9427            height: Some(height),
 9428            render: Arc::new(move |cx| {
 9429                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9430                cloned_prompt.clone().into_any_element()
 9431            }),
 9432            priority: 0,
 9433            render_in_minimap: true,
 9434        }];
 9435
 9436        let focus_handle = bp_prompt.focus_handle(cx);
 9437        window.focus(&focus_handle);
 9438
 9439        let block_ids = self.insert_blocks(blocks, None, cx);
 9440        bp_prompt.update(cx, |prompt, _| {
 9441            prompt.add_block_ids(block_ids);
 9442        });
 9443    }
 9444
 9445    pub(crate) fn breakpoint_at_row(
 9446        &self,
 9447        row: u32,
 9448        window: &mut Window,
 9449        cx: &mut Context<Self>,
 9450    ) -> Option<(Anchor, Breakpoint)> {
 9451        let snapshot = self.snapshot(window, cx);
 9452        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9453
 9454        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9455    }
 9456
 9457    pub(crate) fn breakpoint_at_anchor(
 9458        &self,
 9459        breakpoint_position: Anchor,
 9460        snapshot: &EditorSnapshot,
 9461        cx: &mut Context<Self>,
 9462    ) -> Option<(Anchor, Breakpoint)> {
 9463        let project = self.project.clone()?;
 9464
 9465        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9466            snapshot
 9467                .buffer_snapshot
 9468                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9469        })?;
 9470
 9471        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9472        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9473        let buffer_snapshot = buffer.read(cx).snapshot();
 9474
 9475        let row = buffer_snapshot
 9476            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9477            .row;
 9478
 9479        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9480        let anchor_end = snapshot
 9481            .buffer_snapshot
 9482            .anchor_after(Point::new(row, line_len));
 9483
 9484        let bp = self
 9485            .breakpoint_store
 9486            .as_ref()?
 9487            .read_with(cx, |breakpoint_store, cx| {
 9488                breakpoint_store
 9489                    .breakpoints(
 9490                        &buffer,
 9491                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9492                        &buffer_snapshot,
 9493                        cx,
 9494                    )
 9495                    .next()
 9496                    .and_then(|(bp, _)| {
 9497                        let breakpoint_row = buffer_snapshot
 9498                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9499                            .row;
 9500
 9501                        if breakpoint_row == row {
 9502                            snapshot
 9503                                .buffer_snapshot
 9504                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9505                                .map(|position| (position, bp.bp.clone()))
 9506                        } else {
 9507                            None
 9508                        }
 9509                    })
 9510            });
 9511        bp
 9512    }
 9513
 9514    pub fn edit_log_breakpoint(
 9515        &mut self,
 9516        _: &EditLogBreakpoint,
 9517        window: &mut Window,
 9518        cx: &mut Context<Self>,
 9519    ) {
 9520        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9521            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9522                message: None,
 9523                state: BreakpointState::Enabled,
 9524                condition: None,
 9525                hit_condition: None,
 9526            });
 9527
 9528            self.add_edit_breakpoint_block(
 9529                anchor,
 9530                &breakpoint,
 9531                BreakpointPromptEditAction::Log,
 9532                window,
 9533                cx,
 9534            );
 9535        }
 9536    }
 9537
 9538    fn breakpoints_at_cursors(
 9539        &self,
 9540        window: &mut Window,
 9541        cx: &mut Context<Self>,
 9542    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9543        let snapshot = self.snapshot(window, cx);
 9544        let cursors = self
 9545            .selections
 9546            .disjoint_anchors()
 9547            .into_iter()
 9548            .map(|selection| {
 9549                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9550
 9551                let breakpoint_position = self
 9552                    .breakpoint_at_row(cursor_position.row, window, cx)
 9553                    .map(|bp| bp.0)
 9554                    .unwrap_or_else(|| {
 9555                        snapshot
 9556                            .display_snapshot
 9557                            .buffer_snapshot
 9558                            .anchor_after(Point::new(cursor_position.row, 0))
 9559                    });
 9560
 9561                let breakpoint = self
 9562                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9563                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9564
 9565                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9566            })
 9567            // 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.
 9568            .collect::<HashMap<Anchor, _>>();
 9569
 9570        cursors.into_iter().collect()
 9571    }
 9572
 9573    pub fn enable_breakpoint(
 9574        &mut self,
 9575        _: &crate::actions::EnableBreakpoint,
 9576        window: &mut Window,
 9577        cx: &mut Context<Self>,
 9578    ) {
 9579        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9580            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9581                continue;
 9582            };
 9583            self.edit_breakpoint_at_anchor(
 9584                anchor,
 9585                breakpoint,
 9586                BreakpointEditAction::InvertState,
 9587                cx,
 9588            );
 9589        }
 9590    }
 9591
 9592    pub fn disable_breakpoint(
 9593        &mut self,
 9594        _: &crate::actions::DisableBreakpoint,
 9595        window: &mut Window,
 9596        cx: &mut Context<Self>,
 9597    ) {
 9598        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9599            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9600                continue;
 9601            };
 9602            self.edit_breakpoint_at_anchor(
 9603                anchor,
 9604                breakpoint,
 9605                BreakpointEditAction::InvertState,
 9606                cx,
 9607            );
 9608        }
 9609    }
 9610
 9611    pub fn toggle_breakpoint(
 9612        &mut self,
 9613        _: &crate::actions::ToggleBreakpoint,
 9614        window: &mut Window,
 9615        cx: &mut Context<Self>,
 9616    ) {
 9617        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9618            if let Some(breakpoint) = breakpoint {
 9619                self.edit_breakpoint_at_anchor(
 9620                    anchor,
 9621                    breakpoint,
 9622                    BreakpointEditAction::Toggle,
 9623                    cx,
 9624                );
 9625            } else {
 9626                self.edit_breakpoint_at_anchor(
 9627                    anchor,
 9628                    Breakpoint::new_standard(),
 9629                    BreakpointEditAction::Toggle,
 9630                    cx,
 9631                );
 9632            }
 9633        }
 9634    }
 9635
 9636    pub fn edit_breakpoint_at_anchor(
 9637        &mut self,
 9638        breakpoint_position: Anchor,
 9639        breakpoint: Breakpoint,
 9640        edit_action: BreakpointEditAction,
 9641        cx: &mut Context<Self>,
 9642    ) {
 9643        let Some(breakpoint_store) = &self.breakpoint_store else {
 9644            return;
 9645        };
 9646
 9647        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9648            if breakpoint_position == Anchor::min() {
 9649                self.buffer()
 9650                    .read(cx)
 9651                    .excerpt_buffer_ids()
 9652                    .into_iter()
 9653                    .next()
 9654            } else {
 9655                None
 9656            }
 9657        }) else {
 9658            return;
 9659        };
 9660
 9661        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9662            return;
 9663        };
 9664
 9665        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9666            breakpoint_store.toggle_breakpoint(
 9667                buffer,
 9668                BreakpointWithPosition {
 9669                    position: breakpoint_position.text_anchor,
 9670                    bp: breakpoint,
 9671                },
 9672                edit_action,
 9673                cx,
 9674            );
 9675        });
 9676
 9677        cx.notify();
 9678    }
 9679
 9680    #[cfg(any(test, feature = "test-support"))]
 9681    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9682        self.breakpoint_store.clone()
 9683    }
 9684
 9685    pub fn prepare_restore_change(
 9686        &self,
 9687        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9688        hunk: &MultiBufferDiffHunk,
 9689        cx: &mut App,
 9690    ) -> Option<()> {
 9691        if hunk.is_created_file() {
 9692            return None;
 9693        }
 9694        let buffer = self.buffer.read(cx);
 9695        let diff = buffer.diff_for(hunk.buffer_id)?;
 9696        let buffer = buffer.buffer(hunk.buffer_id)?;
 9697        let buffer = buffer.read(cx);
 9698        let original_text = diff
 9699            .read(cx)
 9700            .base_text()
 9701            .as_rope()
 9702            .slice(hunk.diff_base_byte_range.clone());
 9703        let buffer_snapshot = buffer.snapshot();
 9704        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9705        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9706            probe
 9707                .0
 9708                .start
 9709                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9710                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9711        }) {
 9712            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9713            Some(())
 9714        } else {
 9715            None
 9716        }
 9717    }
 9718
 9719    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9720        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9721    }
 9722
 9723    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9724        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9725    }
 9726
 9727    fn manipulate_lines<Fn>(
 9728        &mut self,
 9729        window: &mut Window,
 9730        cx: &mut Context<Self>,
 9731        mut callback: Fn,
 9732    ) where
 9733        Fn: FnMut(&mut Vec<&str>),
 9734    {
 9735        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9736
 9737        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9738        let buffer = self.buffer.read(cx).snapshot(cx);
 9739
 9740        let mut edits = Vec::new();
 9741
 9742        let selections = self.selections.all::<Point>(cx);
 9743        let mut selections = selections.iter().peekable();
 9744        let mut contiguous_row_selections = Vec::new();
 9745        let mut new_selections = Vec::new();
 9746        let mut added_lines = 0;
 9747        let mut removed_lines = 0;
 9748
 9749        while let Some(selection) = selections.next() {
 9750            let (start_row, end_row) = consume_contiguous_rows(
 9751                &mut contiguous_row_selections,
 9752                selection,
 9753                &display_map,
 9754                &mut selections,
 9755            );
 9756
 9757            let start_point = Point::new(start_row.0, 0);
 9758            let end_point = Point::new(
 9759                end_row.previous_row().0,
 9760                buffer.line_len(end_row.previous_row()),
 9761            );
 9762            let text = buffer
 9763                .text_for_range(start_point..end_point)
 9764                .collect::<String>();
 9765
 9766            let mut lines = text.split('\n').collect_vec();
 9767
 9768            let lines_before = lines.len();
 9769            callback(&mut lines);
 9770            let lines_after = lines.len();
 9771
 9772            edits.push((start_point..end_point, lines.join("\n")));
 9773
 9774            // Selections must change based on added and removed line count
 9775            let start_row =
 9776                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9777            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9778            new_selections.push(Selection {
 9779                id: selection.id,
 9780                start: start_row,
 9781                end: end_row,
 9782                goal: SelectionGoal::None,
 9783                reversed: selection.reversed,
 9784            });
 9785
 9786            if lines_after > lines_before {
 9787                added_lines += lines_after - lines_before;
 9788            } else if lines_before > lines_after {
 9789                removed_lines += lines_before - lines_after;
 9790            }
 9791        }
 9792
 9793        self.transact(window, cx, |this, window, cx| {
 9794            let buffer = this.buffer.update(cx, |buffer, cx| {
 9795                buffer.edit(edits, None, cx);
 9796                buffer.snapshot(cx)
 9797            });
 9798
 9799            // Recalculate offsets on newly edited buffer
 9800            let new_selections = new_selections
 9801                .iter()
 9802                .map(|s| {
 9803                    let start_point = Point::new(s.start.0, 0);
 9804                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9805                    Selection {
 9806                        id: s.id,
 9807                        start: buffer.point_to_offset(start_point),
 9808                        end: buffer.point_to_offset(end_point),
 9809                        goal: s.goal,
 9810                        reversed: s.reversed,
 9811                    }
 9812                })
 9813                .collect();
 9814
 9815            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9816                s.select(new_selections);
 9817            });
 9818
 9819            this.request_autoscroll(Autoscroll::fit(), cx);
 9820        });
 9821    }
 9822
 9823    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9824        self.manipulate_text(window, cx, |text| {
 9825            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9826            if has_upper_case_characters {
 9827                text.to_lowercase()
 9828            } else {
 9829                text.to_uppercase()
 9830            }
 9831        })
 9832    }
 9833
 9834    pub fn convert_to_upper_case(
 9835        &mut self,
 9836        _: &ConvertToUpperCase,
 9837        window: &mut Window,
 9838        cx: &mut Context<Self>,
 9839    ) {
 9840        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9841    }
 9842
 9843    pub fn convert_to_lower_case(
 9844        &mut self,
 9845        _: &ConvertToLowerCase,
 9846        window: &mut Window,
 9847        cx: &mut Context<Self>,
 9848    ) {
 9849        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9850    }
 9851
 9852    pub fn convert_to_title_case(
 9853        &mut self,
 9854        _: &ConvertToTitleCase,
 9855        window: &mut Window,
 9856        cx: &mut Context<Self>,
 9857    ) {
 9858        self.manipulate_text(window, cx, |text| {
 9859            text.split('\n')
 9860                .map(|line| line.to_case(Case::Title))
 9861                .join("\n")
 9862        })
 9863    }
 9864
 9865    pub fn convert_to_snake_case(
 9866        &mut self,
 9867        _: &ConvertToSnakeCase,
 9868        window: &mut Window,
 9869        cx: &mut Context<Self>,
 9870    ) {
 9871        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
 9872    }
 9873
 9874    pub fn convert_to_kebab_case(
 9875        &mut self,
 9876        _: &ConvertToKebabCase,
 9877        window: &mut Window,
 9878        cx: &mut Context<Self>,
 9879    ) {
 9880        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
 9881    }
 9882
 9883    pub fn convert_to_upper_camel_case(
 9884        &mut self,
 9885        _: &ConvertToUpperCamelCase,
 9886        window: &mut Window,
 9887        cx: &mut Context<Self>,
 9888    ) {
 9889        self.manipulate_text(window, cx, |text| {
 9890            text.split('\n')
 9891                .map(|line| line.to_case(Case::UpperCamel))
 9892                .join("\n")
 9893        })
 9894    }
 9895
 9896    pub fn convert_to_lower_camel_case(
 9897        &mut self,
 9898        _: &ConvertToLowerCamelCase,
 9899        window: &mut Window,
 9900        cx: &mut Context<Self>,
 9901    ) {
 9902        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
 9903    }
 9904
 9905    pub fn convert_to_opposite_case(
 9906        &mut self,
 9907        _: &ConvertToOppositeCase,
 9908        window: &mut Window,
 9909        cx: &mut Context<Self>,
 9910    ) {
 9911        self.manipulate_text(window, cx, |text| {
 9912            text.chars()
 9913                .fold(String::with_capacity(text.len()), |mut t, c| {
 9914                    if c.is_uppercase() {
 9915                        t.extend(c.to_lowercase());
 9916                    } else {
 9917                        t.extend(c.to_uppercase());
 9918                    }
 9919                    t
 9920                })
 9921        })
 9922    }
 9923
 9924    pub fn convert_to_rot13(
 9925        &mut self,
 9926        _: &ConvertToRot13,
 9927        window: &mut Window,
 9928        cx: &mut Context<Self>,
 9929    ) {
 9930        self.manipulate_text(window, cx, |text| {
 9931            text.chars()
 9932                .map(|c| match c {
 9933                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
 9934                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
 9935                    _ => c,
 9936                })
 9937                .collect()
 9938        })
 9939    }
 9940
 9941    pub fn convert_to_rot47(
 9942        &mut self,
 9943        _: &ConvertToRot47,
 9944        window: &mut Window,
 9945        cx: &mut Context<Self>,
 9946    ) {
 9947        self.manipulate_text(window, cx, |text| {
 9948            text.chars()
 9949                .map(|c| {
 9950                    let code_point = c as u32;
 9951                    if code_point >= 33 && code_point <= 126 {
 9952                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
 9953                    }
 9954                    c
 9955                })
 9956                .collect()
 9957        })
 9958    }
 9959
 9960    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
 9961    where
 9962        Fn: FnMut(&str) -> String,
 9963    {
 9964        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9965        let buffer = self.buffer.read(cx).snapshot(cx);
 9966
 9967        let mut new_selections = Vec::new();
 9968        let mut edits = Vec::new();
 9969        let mut selection_adjustment = 0i32;
 9970
 9971        for selection in self.selections.all::<usize>(cx) {
 9972            let selection_is_empty = selection.is_empty();
 9973
 9974            let (start, end) = if selection_is_empty {
 9975                let word_range = movement::surrounding_word(
 9976                    &display_map,
 9977                    selection.start.to_display_point(&display_map),
 9978                );
 9979                let start = word_range.start.to_offset(&display_map, Bias::Left);
 9980                let end = word_range.end.to_offset(&display_map, Bias::Left);
 9981                (start, end)
 9982            } else {
 9983                (selection.start, selection.end)
 9984            };
 9985
 9986            let text = buffer.text_for_range(start..end).collect::<String>();
 9987            let old_length = text.len() as i32;
 9988            let text = callback(&text);
 9989
 9990            new_selections.push(Selection {
 9991                start: (start as i32 - selection_adjustment) as usize,
 9992                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 9993                goal: SelectionGoal::None,
 9994                ..selection
 9995            });
 9996
 9997            selection_adjustment += old_length - text.len() as i32;
 9998
 9999            edits.push((start..end, text));
10000        }
10001
10002        self.transact(window, cx, |this, window, cx| {
10003            this.buffer.update(cx, |buffer, cx| {
10004                buffer.edit(edits, None, cx);
10005            });
10006
10007            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10008                s.select(new_selections);
10009            });
10010
10011            this.request_autoscroll(Autoscroll::fit(), cx);
10012        });
10013    }
10014
10015    pub fn duplicate(
10016        &mut self,
10017        upwards: bool,
10018        whole_lines: bool,
10019        window: &mut Window,
10020        cx: &mut Context<Self>,
10021    ) {
10022        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10023
10024        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10025        let buffer = &display_map.buffer_snapshot;
10026        let selections = self.selections.all::<Point>(cx);
10027
10028        let mut edits = Vec::new();
10029        let mut selections_iter = selections.iter().peekable();
10030        while let Some(selection) = selections_iter.next() {
10031            let mut rows = selection.spanned_rows(false, &display_map);
10032            // duplicate line-wise
10033            if whole_lines || selection.start == selection.end {
10034                // Avoid duplicating the same lines twice.
10035                while let Some(next_selection) = selections_iter.peek() {
10036                    let next_rows = next_selection.spanned_rows(false, &display_map);
10037                    if next_rows.start < rows.end {
10038                        rows.end = next_rows.end;
10039                        selections_iter.next().unwrap();
10040                    } else {
10041                        break;
10042                    }
10043                }
10044
10045                // Copy the text from the selected row region and splice it either at the start
10046                // or end of the region.
10047                let start = Point::new(rows.start.0, 0);
10048                let end = Point::new(
10049                    rows.end.previous_row().0,
10050                    buffer.line_len(rows.end.previous_row()),
10051                );
10052                let text = buffer
10053                    .text_for_range(start..end)
10054                    .chain(Some("\n"))
10055                    .collect::<String>();
10056                let insert_location = if upwards {
10057                    Point::new(rows.end.0, 0)
10058                } else {
10059                    start
10060                };
10061                edits.push((insert_location..insert_location, text));
10062            } else {
10063                // duplicate character-wise
10064                let start = selection.start;
10065                let end = selection.end;
10066                let text = buffer.text_for_range(start..end).collect::<String>();
10067                edits.push((selection.end..selection.end, text));
10068            }
10069        }
10070
10071        self.transact(window, cx, |this, _, cx| {
10072            this.buffer.update(cx, |buffer, cx| {
10073                buffer.edit(edits, None, cx);
10074            });
10075
10076            this.request_autoscroll(Autoscroll::fit(), cx);
10077        });
10078    }
10079
10080    pub fn duplicate_line_up(
10081        &mut self,
10082        _: &DuplicateLineUp,
10083        window: &mut Window,
10084        cx: &mut Context<Self>,
10085    ) {
10086        self.duplicate(true, true, window, cx);
10087    }
10088
10089    pub fn duplicate_line_down(
10090        &mut self,
10091        _: &DuplicateLineDown,
10092        window: &mut Window,
10093        cx: &mut Context<Self>,
10094    ) {
10095        self.duplicate(false, true, window, cx);
10096    }
10097
10098    pub fn duplicate_selection(
10099        &mut self,
10100        _: &DuplicateSelection,
10101        window: &mut Window,
10102        cx: &mut Context<Self>,
10103    ) {
10104        self.duplicate(false, false, window, cx);
10105    }
10106
10107    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10108        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10109
10110        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10111        let buffer = self.buffer.read(cx).snapshot(cx);
10112
10113        let mut edits = Vec::new();
10114        let mut unfold_ranges = Vec::new();
10115        let mut refold_creases = Vec::new();
10116
10117        let selections = self.selections.all::<Point>(cx);
10118        let mut selections = selections.iter().peekable();
10119        let mut contiguous_row_selections = Vec::new();
10120        let mut new_selections = Vec::new();
10121
10122        while let Some(selection) = selections.next() {
10123            // Find all the selections that span a contiguous row range
10124            let (start_row, end_row) = consume_contiguous_rows(
10125                &mut contiguous_row_selections,
10126                selection,
10127                &display_map,
10128                &mut selections,
10129            );
10130
10131            // Move the text spanned by the row range to be before the line preceding the row range
10132            if start_row.0 > 0 {
10133                let range_to_move = Point::new(
10134                    start_row.previous_row().0,
10135                    buffer.line_len(start_row.previous_row()),
10136                )
10137                    ..Point::new(
10138                        end_row.previous_row().0,
10139                        buffer.line_len(end_row.previous_row()),
10140                    );
10141                let insertion_point = display_map
10142                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10143                    .0;
10144
10145                // Don't move lines across excerpts
10146                if buffer
10147                    .excerpt_containing(insertion_point..range_to_move.end)
10148                    .is_some()
10149                {
10150                    let text = buffer
10151                        .text_for_range(range_to_move.clone())
10152                        .flat_map(|s| s.chars())
10153                        .skip(1)
10154                        .chain(['\n'])
10155                        .collect::<String>();
10156
10157                    edits.push((
10158                        buffer.anchor_after(range_to_move.start)
10159                            ..buffer.anchor_before(range_to_move.end),
10160                        String::new(),
10161                    ));
10162                    let insertion_anchor = buffer.anchor_after(insertion_point);
10163                    edits.push((insertion_anchor..insertion_anchor, text));
10164
10165                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10166
10167                    // Move selections up
10168                    new_selections.extend(contiguous_row_selections.drain(..).map(
10169                        |mut selection| {
10170                            selection.start.row -= row_delta;
10171                            selection.end.row -= row_delta;
10172                            selection
10173                        },
10174                    ));
10175
10176                    // Move folds up
10177                    unfold_ranges.push(range_to_move.clone());
10178                    for fold in display_map.folds_in_range(
10179                        buffer.anchor_before(range_to_move.start)
10180                            ..buffer.anchor_after(range_to_move.end),
10181                    ) {
10182                        let mut start = fold.range.start.to_point(&buffer);
10183                        let mut end = fold.range.end.to_point(&buffer);
10184                        start.row -= row_delta;
10185                        end.row -= row_delta;
10186                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10187                    }
10188                }
10189            }
10190
10191            // If we didn't move line(s), preserve the existing selections
10192            new_selections.append(&mut contiguous_row_selections);
10193        }
10194
10195        self.transact(window, cx, |this, window, cx| {
10196            this.unfold_ranges(&unfold_ranges, true, true, cx);
10197            this.buffer.update(cx, |buffer, cx| {
10198                for (range, text) in edits {
10199                    buffer.edit([(range, text)], None, cx);
10200                }
10201            });
10202            this.fold_creases(refold_creases, true, window, cx);
10203            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10204                s.select(new_selections);
10205            })
10206        });
10207    }
10208
10209    pub fn move_line_down(
10210        &mut self,
10211        _: &MoveLineDown,
10212        window: &mut Window,
10213        cx: &mut Context<Self>,
10214    ) {
10215        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10216
10217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10218        let buffer = self.buffer.read(cx).snapshot(cx);
10219
10220        let mut edits = Vec::new();
10221        let mut unfold_ranges = Vec::new();
10222        let mut refold_creases = Vec::new();
10223
10224        let selections = self.selections.all::<Point>(cx);
10225        let mut selections = selections.iter().peekable();
10226        let mut contiguous_row_selections = Vec::new();
10227        let mut new_selections = Vec::new();
10228
10229        while let Some(selection) = selections.next() {
10230            // Find all the selections that span a contiguous row range
10231            let (start_row, end_row) = consume_contiguous_rows(
10232                &mut contiguous_row_selections,
10233                selection,
10234                &display_map,
10235                &mut selections,
10236            );
10237
10238            // Move the text spanned by the row range to be after the last line of the row range
10239            if end_row.0 <= buffer.max_point().row {
10240                let range_to_move =
10241                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10242                let insertion_point = display_map
10243                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10244                    .0;
10245
10246                // Don't move lines across excerpt boundaries
10247                if buffer
10248                    .excerpt_containing(range_to_move.start..insertion_point)
10249                    .is_some()
10250                {
10251                    let mut text = String::from("\n");
10252                    text.extend(buffer.text_for_range(range_to_move.clone()));
10253                    text.pop(); // Drop trailing newline
10254                    edits.push((
10255                        buffer.anchor_after(range_to_move.start)
10256                            ..buffer.anchor_before(range_to_move.end),
10257                        String::new(),
10258                    ));
10259                    let insertion_anchor = buffer.anchor_after(insertion_point);
10260                    edits.push((insertion_anchor..insertion_anchor, text));
10261
10262                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10263
10264                    // Move selections down
10265                    new_selections.extend(contiguous_row_selections.drain(..).map(
10266                        |mut selection| {
10267                            selection.start.row += row_delta;
10268                            selection.end.row += row_delta;
10269                            selection
10270                        },
10271                    ));
10272
10273                    // Move folds down
10274                    unfold_ranges.push(range_to_move.clone());
10275                    for fold in display_map.folds_in_range(
10276                        buffer.anchor_before(range_to_move.start)
10277                            ..buffer.anchor_after(range_to_move.end),
10278                    ) {
10279                        let mut start = fold.range.start.to_point(&buffer);
10280                        let mut end = fold.range.end.to_point(&buffer);
10281                        start.row += row_delta;
10282                        end.row += row_delta;
10283                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10284                    }
10285                }
10286            }
10287
10288            // If we didn't move line(s), preserve the existing selections
10289            new_selections.append(&mut contiguous_row_selections);
10290        }
10291
10292        self.transact(window, cx, |this, window, cx| {
10293            this.unfold_ranges(&unfold_ranges, true, true, cx);
10294            this.buffer.update(cx, |buffer, cx| {
10295                for (range, text) in edits {
10296                    buffer.edit([(range, text)], None, cx);
10297                }
10298            });
10299            this.fold_creases(refold_creases, true, window, cx);
10300            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10301                s.select(new_selections)
10302            });
10303        });
10304    }
10305
10306    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10307        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10308        let text_layout_details = &self.text_layout_details(window);
10309        self.transact(window, cx, |this, window, cx| {
10310            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10311                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10312                s.move_with(|display_map, selection| {
10313                    if !selection.is_empty() {
10314                        return;
10315                    }
10316
10317                    let mut head = selection.head();
10318                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10319                    if head.column() == display_map.line_len(head.row()) {
10320                        transpose_offset = display_map
10321                            .buffer_snapshot
10322                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10323                    }
10324
10325                    if transpose_offset == 0 {
10326                        return;
10327                    }
10328
10329                    *head.column_mut() += 1;
10330                    head = display_map.clip_point(head, Bias::Right);
10331                    let goal = SelectionGoal::HorizontalPosition(
10332                        display_map
10333                            .x_for_display_point(head, text_layout_details)
10334                            .into(),
10335                    );
10336                    selection.collapse_to(head, goal);
10337
10338                    let transpose_start = display_map
10339                        .buffer_snapshot
10340                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10341                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10342                        let transpose_end = display_map
10343                            .buffer_snapshot
10344                            .clip_offset(transpose_offset + 1, Bias::Right);
10345                        if let Some(ch) =
10346                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10347                        {
10348                            edits.push((transpose_start..transpose_offset, String::new()));
10349                            edits.push((transpose_end..transpose_end, ch.to_string()));
10350                        }
10351                    }
10352                });
10353                edits
10354            });
10355            this.buffer
10356                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10357            let selections = this.selections.all::<usize>(cx);
10358            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10359                s.select(selections);
10360            });
10361        });
10362    }
10363
10364    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10365        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10366        self.rewrap_impl(RewrapOptions::default(), cx)
10367    }
10368
10369    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10370        let buffer = self.buffer.read(cx).snapshot(cx);
10371        let selections = self.selections.all::<Point>(cx);
10372        let mut selections = selections.iter().peekable();
10373
10374        let mut edits = Vec::new();
10375        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10376
10377        while let Some(selection) = selections.next() {
10378            let mut start_row = selection.start.row;
10379            let mut end_row = selection.end.row;
10380
10381            // Skip selections that overlap with a range that has already been rewrapped.
10382            let selection_range = start_row..end_row;
10383            if rewrapped_row_ranges
10384                .iter()
10385                .any(|range| range.overlaps(&selection_range))
10386            {
10387                continue;
10388            }
10389
10390            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10391
10392            // Since not all lines in the selection may be at the same indent
10393            // level, choose the indent size that is the most common between all
10394            // of the lines.
10395            //
10396            // If there is a tie, we use the deepest indent.
10397            let (indent_size, indent_end) = {
10398                let mut indent_size_occurrences = HashMap::default();
10399                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10400
10401                for row in start_row..=end_row {
10402                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10403                    rows_by_indent_size.entry(indent).or_default().push(row);
10404                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10405                }
10406
10407                let indent_size = indent_size_occurrences
10408                    .into_iter()
10409                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10410                    .map(|(indent, _)| indent)
10411                    .unwrap_or_default();
10412                let row = rows_by_indent_size[&indent_size][0];
10413                let indent_end = Point::new(row, indent_size.len);
10414
10415                (indent_size, indent_end)
10416            };
10417
10418            let mut line_prefix = indent_size.chars().collect::<String>();
10419
10420            let mut inside_comment = false;
10421            if let Some(comment_prefix) =
10422                buffer
10423                    .language_scope_at(selection.head())
10424                    .and_then(|language| {
10425                        language
10426                            .line_comment_prefixes()
10427                            .iter()
10428                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10429                            .cloned()
10430                    })
10431            {
10432                line_prefix.push_str(&comment_prefix);
10433                inside_comment = true;
10434            }
10435
10436            let language_settings = buffer.language_settings_at(selection.head(), cx);
10437            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10438                RewrapBehavior::InComments => inside_comment,
10439                RewrapBehavior::InSelections => !selection.is_empty(),
10440                RewrapBehavior::Anywhere => true,
10441            };
10442
10443            let should_rewrap = options.override_language_settings
10444                || allow_rewrap_based_on_language
10445                || self.hard_wrap.is_some();
10446            if !should_rewrap {
10447                continue;
10448            }
10449
10450            if selection.is_empty() {
10451                'expand_upwards: while start_row > 0 {
10452                    let prev_row = start_row - 1;
10453                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10454                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10455                    {
10456                        start_row = prev_row;
10457                    } else {
10458                        break 'expand_upwards;
10459                    }
10460                }
10461
10462                'expand_downwards: while end_row < buffer.max_point().row {
10463                    let next_row = end_row + 1;
10464                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10465                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10466                    {
10467                        end_row = next_row;
10468                    } else {
10469                        break 'expand_downwards;
10470                    }
10471                }
10472            }
10473
10474            let start = Point::new(start_row, 0);
10475            let start_offset = start.to_offset(&buffer);
10476            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10477            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10478            let Some(lines_without_prefixes) = selection_text
10479                .lines()
10480                .map(|line| {
10481                    line.strip_prefix(&line_prefix)
10482                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10483                        .ok_or_else(|| {
10484                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
10485                        })
10486                })
10487                .collect::<Result<Vec<_>, _>>()
10488                .log_err()
10489            else {
10490                continue;
10491            };
10492
10493            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10494                buffer
10495                    .language_settings_at(Point::new(start_row, 0), cx)
10496                    .preferred_line_length as usize
10497            });
10498            let wrapped_text = wrap_with_prefix(
10499                line_prefix,
10500                lines_without_prefixes.join("\n"),
10501                wrap_column,
10502                tab_size,
10503                options.preserve_existing_whitespace,
10504            );
10505
10506            // TODO: should always use char-based diff while still supporting cursor behavior that
10507            // matches vim.
10508            let mut diff_options = DiffOptions::default();
10509            if options.override_language_settings {
10510                diff_options.max_word_diff_len = 0;
10511                diff_options.max_word_diff_line_count = 0;
10512            } else {
10513                diff_options.max_word_diff_len = usize::MAX;
10514                diff_options.max_word_diff_line_count = usize::MAX;
10515            }
10516
10517            for (old_range, new_text) in
10518                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10519            {
10520                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10521                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10522                edits.push((edit_start..edit_end, new_text));
10523            }
10524
10525            rewrapped_row_ranges.push(start_row..=end_row);
10526        }
10527
10528        self.buffer
10529            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10530    }
10531
10532    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10533        let mut text = String::new();
10534        let buffer = self.buffer.read(cx).snapshot(cx);
10535        let mut selections = self.selections.all::<Point>(cx);
10536        let mut clipboard_selections = Vec::with_capacity(selections.len());
10537        {
10538            let max_point = buffer.max_point();
10539            let mut is_first = true;
10540            for selection in &mut selections {
10541                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10542                if is_entire_line {
10543                    selection.start = Point::new(selection.start.row, 0);
10544                    if !selection.is_empty() && selection.end.column == 0 {
10545                        selection.end = cmp::min(max_point, selection.end);
10546                    } else {
10547                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10548                    }
10549                    selection.goal = SelectionGoal::None;
10550                }
10551                if is_first {
10552                    is_first = false;
10553                } else {
10554                    text += "\n";
10555                }
10556                let mut len = 0;
10557                for chunk in buffer.text_for_range(selection.start..selection.end) {
10558                    text.push_str(chunk);
10559                    len += chunk.len();
10560                }
10561                clipboard_selections.push(ClipboardSelection {
10562                    len,
10563                    is_entire_line,
10564                    first_line_indent: buffer
10565                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10566                        .len,
10567                });
10568            }
10569        }
10570
10571        self.transact(window, cx, |this, window, cx| {
10572            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10573                s.select(selections);
10574            });
10575            this.insert("", window, cx);
10576        });
10577        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10578    }
10579
10580    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10581        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10582        let item = self.cut_common(window, cx);
10583        cx.write_to_clipboard(item);
10584    }
10585
10586    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10587        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10588        self.change_selections(None, window, cx, |s| {
10589            s.move_with(|snapshot, sel| {
10590                if sel.is_empty() {
10591                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10592                }
10593            });
10594        });
10595        let item = self.cut_common(window, cx);
10596        cx.set_global(KillRing(item))
10597    }
10598
10599    pub fn kill_ring_yank(
10600        &mut self,
10601        _: &KillRingYank,
10602        window: &mut Window,
10603        cx: &mut Context<Self>,
10604    ) {
10605        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10606        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10607            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10608                (kill_ring.text().to_string(), kill_ring.metadata_json())
10609            } else {
10610                return;
10611            }
10612        } else {
10613            return;
10614        };
10615        self.do_paste(&text, metadata, false, window, cx);
10616    }
10617
10618    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10619        self.do_copy(true, cx);
10620    }
10621
10622    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10623        self.do_copy(false, cx);
10624    }
10625
10626    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10627        let selections = self.selections.all::<Point>(cx);
10628        let buffer = self.buffer.read(cx).read(cx);
10629        let mut text = String::new();
10630
10631        let mut clipboard_selections = Vec::with_capacity(selections.len());
10632        {
10633            let max_point = buffer.max_point();
10634            let mut is_first = true;
10635            for selection in &selections {
10636                let mut start = selection.start;
10637                let mut end = selection.end;
10638                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10639                if is_entire_line {
10640                    start = Point::new(start.row, 0);
10641                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10642                }
10643
10644                let mut trimmed_selections = Vec::new();
10645                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10646                    let row = MultiBufferRow(start.row);
10647                    let first_indent = buffer.indent_size_for_line(row);
10648                    if first_indent.len == 0 || start.column > first_indent.len {
10649                        trimmed_selections.push(start..end);
10650                    } else {
10651                        trimmed_selections.push(
10652                            Point::new(row.0, first_indent.len)
10653                                ..Point::new(row.0, buffer.line_len(row)),
10654                        );
10655                        for row in start.row + 1..=end.row {
10656                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10657                            if row == end.row {
10658                                line_len = end.column;
10659                            }
10660                            if line_len == 0 {
10661                                trimmed_selections
10662                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10663                                continue;
10664                            }
10665                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10666                            if row_indent_size.len >= first_indent.len {
10667                                trimmed_selections.push(
10668                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10669                                );
10670                            } else {
10671                                trimmed_selections.clear();
10672                                trimmed_selections.push(start..end);
10673                                break;
10674                            }
10675                        }
10676                    }
10677                } else {
10678                    trimmed_selections.push(start..end);
10679                }
10680
10681                for trimmed_range in trimmed_selections {
10682                    if is_first {
10683                        is_first = false;
10684                    } else {
10685                        text += "\n";
10686                    }
10687                    let mut len = 0;
10688                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10689                        text.push_str(chunk);
10690                        len += chunk.len();
10691                    }
10692                    clipboard_selections.push(ClipboardSelection {
10693                        len,
10694                        is_entire_line,
10695                        first_line_indent: buffer
10696                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10697                            .len,
10698                    });
10699                }
10700            }
10701        }
10702
10703        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10704            text,
10705            clipboard_selections,
10706        ));
10707    }
10708
10709    pub fn do_paste(
10710        &mut self,
10711        text: &String,
10712        clipboard_selections: Option<Vec<ClipboardSelection>>,
10713        handle_entire_lines: bool,
10714        window: &mut Window,
10715        cx: &mut Context<Self>,
10716    ) {
10717        if self.read_only(cx) {
10718            return;
10719        }
10720
10721        let clipboard_text = Cow::Borrowed(text);
10722
10723        self.transact(window, cx, |this, window, cx| {
10724            if let Some(mut clipboard_selections) = clipboard_selections {
10725                let old_selections = this.selections.all::<usize>(cx);
10726                let all_selections_were_entire_line =
10727                    clipboard_selections.iter().all(|s| s.is_entire_line);
10728                let first_selection_indent_column =
10729                    clipboard_selections.first().map(|s| s.first_line_indent);
10730                if clipboard_selections.len() != old_selections.len() {
10731                    clipboard_selections.drain(..);
10732                }
10733                let cursor_offset = this.selections.last::<usize>(cx).head();
10734                let mut auto_indent_on_paste = true;
10735
10736                this.buffer.update(cx, |buffer, cx| {
10737                    let snapshot = buffer.read(cx);
10738                    auto_indent_on_paste = snapshot
10739                        .language_settings_at(cursor_offset, cx)
10740                        .auto_indent_on_paste;
10741
10742                    let mut start_offset = 0;
10743                    let mut edits = Vec::new();
10744                    let mut original_indent_columns = Vec::new();
10745                    for (ix, selection) in old_selections.iter().enumerate() {
10746                        let to_insert;
10747                        let entire_line;
10748                        let original_indent_column;
10749                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10750                            let end_offset = start_offset + clipboard_selection.len;
10751                            to_insert = &clipboard_text[start_offset..end_offset];
10752                            entire_line = clipboard_selection.is_entire_line;
10753                            start_offset = end_offset + 1;
10754                            original_indent_column = Some(clipboard_selection.first_line_indent);
10755                        } else {
10756                            to_insert = clipboard_text.as_str();
10757                            entire_line = all_selections_were_entire_line;
10758                            original_indent_column = first_selection_indent_column
10759                        }
10760
10761                        // If the corresponding selection was empty when this slice of the
10762                        // clipboard text was written, then the entire line containing the
10763                        // selection was copied. If this selection is also currently empty,
10764                        // then paste the line before the current line of the buffer.
10765                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10766                            let column = selection.start.to_point(&snapshot).column as usize;
10767                            let line_start = selection.start - column;
10768                            line_start..line_start
10769                        } else {
10770                            selection.range()
10771                        };
10772
10773                        edits.push((range, to_insert));
10774                        original_indent_columns.push(original_indent_column);
10775                    }
10776                    drop(snapshot);
10777
10778                    buffer.edit(
10779                        edits,
10780                        if auto_indent_on_paste {
10781                            Some(AutoindentMode::Block {
10782                                original_indent_columns,
10783                            })
10784                        } else {
10785                            None
10786                        },
10787                        cx,
10788                    );
10789                });
10790
10791                let selections = this.selections.all::<usize>(cx);
10792                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10793                    s.select(selections)
10794                });
10795            } else {
10796                this.insert(&clipboard_text, window, cx);
10797            }
10798        });
10799    }
10800
10801    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10802        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10803        if let Some(item) = cx.read_from_clipboard() {
10804            let entries = item.entries();
10805
10806            match entries.first() {
10807                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10808                // of all the pasted entries.
10809                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10810                    .do_paste(
10811                        clipboard_string.text(),
10812                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10813                        true,
10814                        window,
10815                        cx,
10816                    ),
10817                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10818            }
10819        }
10820    }
10821
10822    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10823        if self.read_only(cx) {
10824            return;
10825        }
10826
10827        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10828
10829        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10830            if let Some((selections, _)) =
10831                self.selection_history.transaction(transaction_id).cloned()
10832            {
10833                self.change_selections(None, window, cx, |s| {
10834                    s.select_anchors(selections.to_vec());
10835                });
10836            } else {
10837                log::error!(
10838                    "No entry in selection_history found for undo. \
10839                     This may correspond to a bug where undo does not update the selection. \
10840                     If this is occurring, please add details to \
10841                     https://github.com/zed-industries/zed/issues/22692"
10842                );
10843            }
10844            self.request_autoscroll(Autoscroll::fit(), cx);
10845            self.unmark_text(window, cx);
10846            self.refresh_inline_completion(true, false, window, cx);
10847            cx.emit(EditorEvent::Edited { transaction_id });
10848            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10849        }
10850    }
10851
10852    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
10853        if self.read_only(cx) {
10854            return;
10855        }
10856
10857        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10858
10859        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
10860            if let Some((_, Some(selections))) =
10861                self.selection_history.transaction(transaction_id).cloned()
10862            {
10863                self.change_selections(None, window, cx, |s| {
10864                    s.select_anchors(selections.to_vec());
10865                });
10866            } else {
10867                log::error!(
10868                    "No entry in selection_history found for redo. \
10869                     This may correspond to a bug where undo does not update the selection. \
10870                     If this is occurring, please add details to \
10871                     https://github.com/zed-industries/zed/issues/22692"
10872                );
10873            }
10874            self.request_autoscroll(Autoscroll::fit(), cx);
10875            self.unmark_text(window, cx);
10876            self.refresh_inline_completion(true, false, window, cx);
10877            cx.emit(EditorEvent::Edited { transaction_id });
10878        }
10879    }
10880
10881    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
10882        self.buffer
10883            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
10884    }
10885
10886    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
10887        self.buffer
10888            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
10889    }
10890
10891    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
10892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10893        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10894            s.move_with(|map, selection| {
10895                let cursor = if selection.is_empty() {
10896                    movement::left(map, selection.start)
10897                } else {
10898                    selection.start
10899                };
10900                selection.collapse_to(cursor, SelectionGoal::None);
10901            });
10902        })
10903    }
10904
10905    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
10906        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10907        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10908            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
10909        })
10910    }
10911
10912    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
10913        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10914        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10915            s.move_with(|map, selection| {
10916                let cursor = if selection.is_empty() {
10917                    movement::right(map, selection.end)
10918                } else {
10919                    selection.end
10920                };
10921                selection.collapse_to(cursor, SelectionGoal::None)
10922            });
10923        })
10924    }
10925
10926    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
10927        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10928        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10929            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
10930        })
10931    }
10932
10933    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
10934        if self.take_rename(true, window, cx).is_some() {
10935            return;
10936        }
10937
10938        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10939            cx.propagate();
10940            return;
10941        }
10942
10943        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10944
10945        let text_layout_details = &self.text_layout_details(window);
10946        let selection_count = self.selections.count();
10947        let first_selection = self.selections.first_anchor();
10948
10949        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10950            s.move_with(|map, selection| {
10951                if !selection.is_empty() {
10952                    selection.goal = SelectionGoal::None;
10953                }
10954                let (cursor, goal) = movement::up(
10955                    map,
10956                    selection.start,
10957                    selection.goal,
10958                    false,
10959                    text_layout_details,
10960                );
10961                selection.collapse_to(cursor, goal);
10962            });
10963        });
10964
10965        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10966        {
10967            cx.propagate();
10968        }
10969    }
10970
10971    pub fn move_up_by_lines(
10972        &mut self,
10973        action: &MoveUpByLines,
10974        window: &mut Window,
10975        cx: &mut Context<Self>,
10976    ) {
10977        if self.take_rename(true, window, cx).is_some() {
10978            return;
10979        }
10980
10981        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10982            cx.propagate();
10983            return;
10984        }
10985
10986        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10987
10988        let text_layout_details = &self.text_layout_details(window);
10989
10990        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10991            s.move_with(|map, selection| {
10992                if !selection.is_empty() {
10993                    selection.goal = SelectionGoal::None;
10994                }
10995                let (cursor, goal) = movement::up_by_rows(
10996                    map,
10997                    selection.start,
10998                    action.lines,
10999                    selection.goal,
11000                    false,
11001                    text_layout_details,
11002                );
11003                selection.collapse_to(cursor, goal);
11004            });
11005        })
11006    }
11007
11008    pub fn move_down_by_lines(
11009        &mut self,
11010        action: &MoveDownByLines,
11011        window: &mut Window,
11012        cx: &mut Context<Self>,
11013    ) {
11014        if self.take_rename(true, window, cx).is_some() {
11015            return;
11016        }
11017
11018        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11019            cx.propagate();
11020            return;
11021        }
11022
11023        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11024
11025        let text_layout_details = &self.text_layout_details(window);
11026
11027        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11028            s.move_with(|map, selection| {
11029                if !selection.is_empty() {
11030                    selection.goal = SelectionGoal::None;
11031                }
11032                let (cursor, goal) = movement::down_by_rows(
11033                    map,
11034                    selection.start,
11035                    action.lines,
11036                    selection.goal,
11037                    false,
11038                    text_layout_details,
11039                );
11040                selection.collapse_to(cursor, goal);
11041            });
11042        })
11043    }
11044
11045    pub fn select_down_by_lines(
11046        &mut self,
11047        action: &SelectDownByLines,
11048        window: &mut Window,
11049        cx: &mut Context<Self>,
11050    ) {
11051        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11052        let text_layout_details = &self.text_layout_details(window);
11053        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11054            s.move_heads_with(|map, head, goal| {
11055                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11056            })
11057        })
11058    }
11059
11060    pub fn select_up_by_lines(
11061        &mut self,
11062        action: &SelectUpByLines,
11063        window: &mut Window,
11064        cx: &mut Context<Self>,
11065    ) {
11066        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11067        let text_layout_details = &self.text_layout_details(window);
11068        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11069            s.move_heads_with(|map, head, goal| {
11070                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11071            })
11072        })
11073    }
11074
11075    pub fn select_page_up(
11076        &mut self,
11077        _: &SelectPageUp,
11078        window: &mut Window,
11079        cx: &mut Context<Self>,
11080    ) {
11081        let Some(row_count) = self.visible_row_count() else {
11082            return;
11083        };
11084
11085        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11086
11087        let text_layout_details = &self.text_layout_details(window);
11088
11089        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11090            s.move_heads_with(|map, head, goal| {
11091                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11092            })
11093        })
11094    }
11095
11096    pub fn move_page_up(
11097        &mut self,
11098        action: &MovePageUp,
11099        window: &mut Window,
11100        cx: &mut Context<Self>,
11101    ) {
11102        if self.take_rename(true, window, cx).is_some() {
11103            return;
11104        }
11105
11106        if self
11107            .context_menu
11108            .borrow_mut()
11109            .as_mut()
11110            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11111            .unwrap_or(false)
11112        {
11113            return;
11114        }
11115
11116        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11117            cx.propagate();
11118            return;
11119        }
11120
11121        let Some(row_count) = self.visible_row_count() else {
11122            return;
11123        };
11124
11125        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11126
11127        let autoscroll = if action.center_cursor {
11128            Autoscroll::center()
11129        } else {
11130            Autoscroll::fit()
11131        };
11132
11133        let text_layout_details = &self.text_layout_details(window);
11134
11135        self.change_selections(Some(autoscroll), window, cx, |s| {
11136            s.move_with(|map, selection| {
11137                if !selection.is_empty() {
11138                    selection.goal = SelectionGoal::None;
11139                }
11140                let (cursor, goal) = movement::up_by_rows(
11141                    map,
11142                    selection.end,
11143                    row_count,
11144                    selection.goal,
11145                    false,
11146                    text_layout_details,
11147                );
11148                selection.collapse_to(cursor, goal);
11149            });
11150        });
11151    }
11152
11153    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11154        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11155        let text_layout_details = &self.text_layout_details(window);
11156        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11157            s.move_heads_with(|map, head, goal| {
11158                movement::up(map, head, goal, false, text_layout_details)
11159            })
11160        })
11161    }
11162
11163    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11164        self.take_rename(true, window, cx);
11165
11166        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11167            cx.propagate();
11168            return;
11169        }
11170
11171        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11172
11173        let text_layout_details = &self.text_layout_details(window);
11174        let selection_count = self.selections.count();
11175        let first_selection = self.selections.first_anchor();
11176
11177        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11178            s.move_with(|map, selection| {
11179                if !selection.is_empty() {
11180                    selection.goal = SelectionGoal::None;
11181                }
11182                let (cursor, goal) = movement::down(
11183                    map,
11184                    selection.end,
11185                    selection.goal,
11186                    false,
11187                    text_layout_details,
11188                );
11189                selection.collapse_to(cursor, goal);
11190            });
11191        });
11192
11193        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11194        {
11195            cx.propagate();
11196        }
11197    }
11198
11199    pub fn select_page_down(
11200        &mut self,
11201        _: &SelectPageDown,
11202        window: &mut Window,
11203        cx: &mut Context<Self>,
11204    ) {
11205        let Some(row_count) = self.visible_row_count() else {
11206            return;
11207        };
11208
11209        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11210
11211        let text_layout_details = &self.text_layout_details(window);
11212
11213        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11214            s.move_heads_with(|map, head, goal| {
11215                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11216            })
11217        })
11218    }
11219
11220    pub fn move_page_down(
11221        &mut self,
11222        action: &MovePageDown,
11223        window: &mut Window,
11224        cx: &mut Context<Self>,
11225    ) {
11226        if self.take_rename(true, window, cx).is_some() {
11227            return;
11228        }
11229
11230        if self
11231            .context_menu
11232            .borrow_mut()
11233            .as_mut()
11234            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11235            .unwrap_or(false)
11236        {
11237            return;
11238        }
11239
11240        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11241            cx.propagate();
11242            return;
11243        }
11244
11245        let Some(row_count) = self.visible_row_count() else {
11246            return;
11247        };
11248
11249        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11250
11251        let autoscroll = if action.center_cursor {
11252            Autoscroll::center()
11253        } else {
11254            Autoscroll::fit()
11255        };
11256
11257        let text_layout_details = &self.text_layout_details(window);
11258        self.change_selections(Some(autoscroll), window, cx, |s| {
11259            s.move_with(|map, selection| {
11260                if !selection.is_empty() {
11261                    selection.goal = SelectionGoal::None;
11262                }
11263                let (cursor, goal) = movement::down_by_rows(
11264                    map,
11265                    selection.end,
11266                    row_count,
11267                    selection.goal,
11268                    false,
11269                    text_layout_details,
11270                );
11271                selection.collapse_to(cursor, goal);
11272            });
11273        });
11274    }
11275
11276    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11277        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11278        let text_layout_details = &self.text_layout_details(window);
11279        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11280            s.move_heads_with(|map, head, goal| {
11281                movement::down(map, head, goal, false, text_layout_details)
11282            })
11283        });
11284    }
11285
11286    pub fn context_menu_first(
11287        &mut self,
11288        _: &ContextMenuFirst,
11289        _window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11293            context_menu.select_first(self.completion_provider.as_deref(), cx);
11294        }
11295    }
11296
11297    pub fn context_menu_prev(
11298        &mut self,
11299        _: &ContextMenuPrevious,
11300        _window: &mut Window,
11301        cx: &mut Context<Self>,
11302    ) {
11303        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11304            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11305        }
11306    }
11307
11308    pub fn context_menu_next(
11309        &mut self,
11310        _: &ContextMenuNext,
11311        _window: &mut Window,
11312        cx: &mut Context<Self>,
11313    ) {
11314        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11315            context_menu.select_next(self.completion_provider.as_deref(), cx);
11316        }
11317    }
11318
11319    pub fn context_menu_last(
11320        &mut self,
11321        _: &ContextMenuLast,
11322        _window: &mut Window,
11323        cx: &mut Context<Self>,
11324    ) {
11325        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11326            context_menu.select_last(self.completion_provider.as_deref(), cx);
11327        }
11328    }
11329
11330    pub fn move_to_previous_word_start(
11331        &mut self,
11332        _: &MoveToPreviousWordStart,
11333        window: &mut Window,
11334        cx: &mut Context<Self>,
11335    ) {
11336        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11337        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11338            s.move_cursors_with(|map, head, _| {
11339                (
11340                    movement::previous_word_start(map, head),
11341                    SelectionGoal::None,
11342                )
11343            });
11344        })
11345    }
11346
11347    pub fn move_to_previous_subword_start(
11348        &mut self,
11349        _: &MoveToPreviousSubwordStart,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11354        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11355            s.move_cursors_with(|map, head, _| {
11356                (
11357                    movement::previous_subword_start(map, head),
11358                    SelectionGoal::None,
11359                )
11360            });
11361        })
11362    }
11363
11364    pub fn select_to_previous_word_start(
11365        &mut self,
11366        _: &SelectToPreviousWordStart,
11367        window: &mut Window,
11368        cx: &mut Context<Self>,
11369    ) {
11370        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11371        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11372            s.move_heads_with(|map, head, _| {
11373                (
11374                    movement::previous_word_start(map, head),
11375                    SelectionGoal::None,
11376                )
11377            });
11378        })
11379    }
11380
11381    pub fn select_to_previous_subword_start(
11382        &mut self,
11383        _: &SelectToPreviousSubwordStart,
11384        window: &mut Window,
11385        cx: &mut Context<Self>,
11386    ) {
11387        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11388        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11389            s.move_heads_with(|map, head, _| {
11390                (
11391                    movement::previous_subword_start(map, head),
11392                    SelectionGoal::None,
11393                )
11394            });
11395        })
11396    }
11397
11398    pub fn delete_to_previous_word_start(
11399        &mut self,
11400        action: &DeleteToPreviousWordStart,
11401        window: &mut Window,
11402        cx: &mut Context<Self>,
11403    ) {
11404        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11405        self.transact(window, cx, |this, window, cx| {
11406            this.select_autoclose_pair(window, cx);
11407            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11408                s.move_with(|map, selection| {
11409                    if selection.is_empty() {
11410                        let cursor = if action.ignore_newlines {
11411                            movement::previous_word_start(map, selection.head())
11412                        } else {
11413                            movement::previous_word_start_or_newline(map, selection.head())
11414                        };
11415                        selection.set_head(cursor, SelectionGoal::None);
11416                    }
11417                });
11418            });
11419            this.insert("", window, cx);
11420        });
11421    }
11422
11423    pub fn delete_to_previous_subword_start(
11424        &mut self,
11425        _: &DeleteToPreviousSubwordStart,
11426        window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11430        self.transact(window, cx, |this, window, cx| {
11431            this.select_autoclose_pair(window, cx);
11432            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11433                s.move_with(|map, selection| {
11434                    if selection.is_empty() {
11435                        let cursor = movement::previous_subword_start(map, selection.head());
11436                        selection.set_head(cursor, SelectionGoal::None);
11437                    }
11438                });
11439            });
11440            this.insert("", window, cx);
11441        });
11442    }
11443
11444    pub fn move_to_next_word_end(
11445        &mut self,
11446        _: &MoveToNextWordEnd,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11451        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11452            s.move_cursors_with(|map, head, _| {
11453                (movement::next_word_end(map, head), SelectionGoal::None)
11454            });
11455        })
11456    }
11457
11458    pub fn move_to_next_subword_end(
11459        &mut self,
11460        _: &MoveToNextSubwordEnd,
11461        window: &mut Window,
11462        cx: &mut Context<Self>,
11463    ) {
11464        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11465        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11466            s.move_cursors_with(|map, head, _| {
11467                (movement::next_subword_end(map, head), SelectionGoal::None)
11468            });
11469        })
11470    }
11471
11472    pub fn select_to_next_word_end(
11473        &mut self,
11474        _: &SelectToNextWordEnd,
11475        window: &mut Window,
11476        cx: &mut Context<Self>,
11477    ) {
11478        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11479        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11480            s.move_heads_with(|map, head, _| {
11481                (movement::next_word_end(map, head), SelectionGoal::None)
11482            });
11483        })
11484    }
11485
11486    pub fn select_to_next_subword_end(
11487        &mut self,
11488        _: &SelectToNextSubwordEnd,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11493        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11494            s.move_heads_with(|map, head, _| {
11495                (movement::next_subword_end(map, head), SelectionGoal::None)
11496            });
11497        })
11498    }
11499
11500    pub fn delete_to_next_word_end(
11501        &mut self,
11502        action: &DeleteToNextWordEnd,
11503        window: &mut Window,
11504        cx: &mut Context<Self>,
11505    ) {
11506        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11507        self.transact(window, cx, |this, window, cx| {
11508            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11509                s.move_with(|map, selection| {
11510                    if selection.is_empty() {
11511                        let cursor = if action.ignore_newlines {
11512                            movement::next_word_end(map, selection.head())
11513                        } else {
11514                            movement::next_word_end_or_newline(map, selection.head())
11515                        };
11516                        selection.set_head(cursor, SelectionGoal::None);
11517                    }
11518                });
11519            });
11520            this.insert("", window, cx);
11521        });
11522    }
11523
11524    pub fn delete_to_next_subword_end(
11525        &mut self,
11526        _: &DeleteToNextSubwordEnd,
11527        window: &mut Window,
11528        cx: &mut Context<Self>,
11529    ) {
11530        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11531        self.transact(window, cx, |this, window, cx| {
11532            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11533                s.move_with(|map, selection| {
11534                    if selection.is_empty() {
11535                        let cursor = movement::next_subword_end(map, selection.head());
11536                        selection.set_head(cursor, SelectionGoal::None);
11537                    }
11538                });
11539            });
11540            this.insert("", window, cx);
11541        });
11542    }
11543
11544    pub fn move_to_beginning_of_line(
11545        &mut self,
11546        action: &MoveToBeginningOfLine,
11547        window: &mut Window,
11548        cx: &mut Context<Self>,
11549    ) {
11550        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11551        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11552            s.move_cursors_with(|map, head, _| {
11553                (
11554                    movement::indented_line_beginning(
11555                        map,
11556                        head,
11557                        action.stop_at_soft_wraps,
11558                        action.stop_at_indent,
11559                    ),
11560                    SelectionGoal::None,
11561                )
11562            });
11563        })
11564    }
11565
11566    pub fn select_to_beginning_of_line(
11567        &mut self,
11568        action: &SelectToBeginningOfLine,
11569        window: &mut Window,
11570        cx: &mut Context<Self>,
11571    ) {
11572        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11573        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11574            s.move_heads_with(|map, head, _| {
11575                (
11576                    movement::indented_line_beginning(
11577                        map,
11578                        head,
11579                        action.stop_at_soft_wraps,
11580                        action.stop_at_indent,
11581                    ),
11582                    SelectionGoal::None,
11583                )
11584            });
11585        });
11586    }
11587
11588    pub fn delete_to_beginning_of_line(
11589        &mut self,
11590        action: &DeleteToBeginningOfLine,
11591        window: &mut Window,
11592        cx: &mut Context<Self>,
11593    ) {
11594        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11595        self.transact(window, cx, |this, window, cx| {
11596            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11597                s.move_with(|_, selection| {
11598                    selection.reversed = true;
11599                });
11600            });
11601
11602            this.select_to_beginning_of_line(
11603                &SelectToBeginningOfLine {
11604                    stop_at_soft_wraps: false,
11605                    stop_at_indent: action.stop_at_indent,
11606                },
11607                window,
11608                cx,
11609            );
11610            this.backspace(&Backspace, window, cx);
11611        });
11612    }
11613
11614    pub fn move_to_end_of_line(
11615        &mut self,
11616        action: &MoveToEndOfLine,
11617        window: &mut Window,
11618        cx: &mut Context<Self>,
11619    ) {
11620        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11621        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11622            s.move_cursors_with(|map, head, _| {
11623                (
11624                    movement::line_end(map, head, action.stop_at_soft_wraps),
11625                    SelectionGoal::None,
11626                )
11627            });
11628        })
11629    }
11630
11631    pub fn select_to_end_of_line(
11632        &mut self,
11633        action: &SelectToEndOfLine,
11634        window: &mut Window,
11635        cx: &mut Context<Self>,
11636    ) {
11637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11638        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11639            s.move_heads_with(|map, head, _| {
11640                (
11641                    movement::line_end(map, head, action.stop_at_soft_wraps),
11642                    SelectionGoal::None,
11643                )
11644            });
11645        })
11646    }
11647
11648    pub fn delete_to_end_of_line(
11649        &mut self,
11650        _: &DeleteToEndOfLine,
11651        window: &mut Window,
11652        cx: &mut Context<Self>,
11653    ) {
11654        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11655        self.transact(window, cx, |this, window, cx| {
11656            this.select_to_end_of_line(
11657                &SelectToEndOfLine {
11658                    stop_at_soft_wraps: false,
11659                },
11660                window,
11661                cx,
11662            );
11663            this.delete(&Delete, window, cx);
11664        });
11665    }
11666
11667    pub fn cut_to_end_of_line(
11668        &mut self,
11669        _: &CutToEndOfLine,
11670        window: &mut Window,
11671        cx: &mut Context<Self>,
11672    ) {
11673        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11674        self.transact(window, cx, |this, window, cx| {
11675            this.select_to_end_of_line(
11676                &SelectToEndOfLine {
11677                    stop_at_soft_wraps: false,
11678                },
11679                window,
11680                cx,
11681            );
11682            this.cut(&Cut, window, cx);
11683        });
11684    }
11685
11686    pub fn move_to_start_of_paragraph(
11687        &mut self,
11688        _: &MoveToStartOfParagraph,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11693            cx.propagate();
11694            return;
11695        }
11696        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11697        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11698            s.move_with(|map, selection| {
11699                selection.collapse_to(
11700                    movement::start_of_paragraph(map, selection.head(), 1),
11701                    SelectionGoal::None,
11702                )
11703            });
11704        })
11705    }
11706
11707    pub fn move_to_end_of_paragraph(
11708        &mut self,
11709        _: &MoveToEndOfParagraph,
11710        window: &mut Window,
11711        cx: &mut Context<Self>,
11712    ) {
11713        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11714            cx.propagate();
11715            return;
11716        }
11717        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11718        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11719            s.move_with(|map, selection| {
11720                selection.collapse_to(
11721                    movement::end_of_paragraph(map, selection.head(), 1),
11722                    SelectionGoal::None,
11723                )
11724            });
11725        })
11726    }
11727
11728    pub fn select_to_start_of_paragraph(
11729        &mut self,
11730        _: &SelectToStartOfParagraph,
11731        window: &mut Window,
11732        cx: &mut Context<Self>,
11733    ) {
11734        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11735            cx.propagate();
11736            return;
11737        }
11738        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11739        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11740            s.move_heads_with(|map, head, _| {
11741                (
11742                    movement::start_of_paragraph(map, head, 1),
11743                    SelectionGoal::None,
11744                )
11745            });
11746        })
11747    }
11748
11749    pub fn select_to_end_of_paragraph(
11750        &mut self,
11751        _: &SelectToEndOfParagraph,
11752        window: &mut Window,
11753        cx: &mut Context<Self>,
11754    ) {
11755        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11756            cx.propagate();
11757            return;
11758        }
11759        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11760        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11761            s.move_heads_with(|map, head, _| {
11762                (
11763                    movement::end_of_paragraph(map, head, 1),
11764                    SelectionGoal::None,
11765                )
11766            });
11767        })
11768    }
11769
11770    pub fn move_to_start_of_excerpt(
11771        &mut self,
11772        _: &MoveToStartOfExcerpt,
11773        window: &mut Window,
11774        cx: &mut Context<Self>,
11775    ) {
11776        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11777            cx.propagate();
11778            return;
11779        }
11780        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11781        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11782            s.move_with(|map, selection| {
11783                selection.collapse_to(
11784                    movement::start_of_excerpt(
11785                        map,
11786                        selection.head(),
11787                        workspace::searchable::Direction::Prev,
11788                    ),
11789                    SelectionGoal::None,
11790                )
11791            });
11792        })
11793    }
11794
11795    pub fn move_to_start_of_next_excerpt(
11796        &mut self,
11797        _: &MoveToStartOfNextExcerpt,
11798        window: &mut Window,
11799        cx: &mut Context<Self>,
11800    ) {
11801        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11802            cx.propagate();
11803            return;
11804        }
11805
11806        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11807            s.move_with(|map, selection| {
11808                selection.collapse_to(
11809                    movement::start_of_excerpt(
11810                        map,
11811                        selection.head(),
11812                        workspace::searchable::Direction::Next,
11813                    ),
11814                    SelectionGoal::None,
11815                )
11816            });
11817        })
11818    }
11819
11820    pub fn move_to_end_of_excerpt(
11821        &mut self,
11822        _: &MoveToEndOfExcerpt,
11823        window: &mut Window,
11824        cx: &mut Context<Self>,
11825    ) {
11826        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11827            cx.propagate();
11828            return;
11829        }
11830        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11831        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11832            s.move_with(|map, selection| {
11833                selection.collapse_to(
11834                    movement::end_of_excerpt(
11835                        map,
11836                        selection.head(),
11837                        workspace::searchable::Direction::Next,
11838                    ),
11839                    SelectionGoal::None,
11840                )
11841            });
11842        })
11843    }
11844
11845    pub fn move_to_end_of_previous_excerpt(
11846        &mut self,
11847        _: &MoveToEndOfPreviousExcerpt,
11848        window: &mut Window,
11849        cx: &mut Context<Self>,
11850    ) {
11851        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11852            cx.propagate();
11853            return;
11854        }
11855        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11856        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11857            s.move_with(|map, selection| {
11858                selection.collapse_to(
11859                    movement::end_of_excerpt(
11860                        map,
11861                        selection.head(),
11862                        workspace::searchable::Direction::Prev,
11863                    ),
11864                    SelectionGoal::None,
11865                )
11866            });
11867        })
11868    }
11869
11870    pub fn select_to_start_of_excerpt(
11871        &mut self,
11872        _: &SelectToStartOfExcerpt,
11873        window: &mut Window,
11874        cx: &mut Context<Self>,
11875    ) {
11876        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11877            cx.propagate();
11878            return;
11879        }
11880        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11881        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11882            s.move_heads_with(|map, head, _| {
11883                (
11884                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11885                    SelectionGoal::None,
11886                )
11887            });
11888        })
11889    }
11890
11891    pub fn select_to_start_of_next_excerpt(
11892        &mut self,
11893        _: &SelectToStartOfNextExcerpt,
11894        window: &mut Window,
11895        cx: &mut Context<Self>,
11896    ) {
11897        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11898            cx.propagate();
11899            return;
11900        }
11901        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11902        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11903            s.move_heads_with(|map, head, _| {
11904                (
11905                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
11906                    SelectionGoal::None,
11907                )
11908            });
11909        })
11910    }
11911
11912    pub fn select_to_end_of_excerpt(
11913        &mut self,
11914        _: &SelectToEndOfExcerpt,
11915        window: &mut Window,
11916        cx: &mut Context<Self>,
11917    ) {
11918        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11919            cx.propagate();
11920            return;
11921        }
11922        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11923        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11924            s.move_heads_with(|map, head, _| {
11925                (
11926                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
11927                    SelectionGoal::None,
11928                )
11929            });
11930        })
11931    }
11932
11933    pub fn select_to_end_of_previous_excerpt(
11934        &mut self,
11935        _: &SelectToEndOfPreviousExcerpt,
11936        window: &mut Window,
11937        cx: &mut Context<Self>,
11938    ) {
11939        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11940            cx.propagate();
11941            return;
11942        }
11943        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11944        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11945            s.move_heads_with(|map, head, _| {
11946                (
11947                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11948                    SelectionGoal::None,
11949                )
11950            });
11951        })
11952    }
11953
11954    pub fn move_to_beginning(
11955        &mut self,
11956        _: &MoveToBeginning,
11957        window: &mut Window,
11958        cx: &mut Context<Self>,
11959    ) {
11960        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11961            cx.propagate();
11962            return;
11963        }
11964        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11965        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11966            s.select_ranges(vec![0..0]);
11967        });
11968    }
11969
11970    pub fn select_to_beginning(
11971        &mut self,
11972        _: &SelectToBeginning,
11973        window: &mut Window,
11974        cx: &mut Context<Self>,
11975    ) {
11976        let mut selection = self.selections.last::<Point>(cx);
11977        selection.set_head(Point::zero(), SelectionGoal::None);
11978        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11979        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11980            s.select(vec![selection]);
11981        });
11982    }
11983
11984    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
11985        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11986            cx.propagate();
11987            return;
11988        }
11989        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11990        let cursor = self.buffer.read(cx).read(cx).len();
11991        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11992            s.select_ranges(vec![cursor..cursor])
11993        });
11994    }
11995
11996    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
11997        self.nav_history = nav_history;
11998    }
11999
12000    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12001        self.nav_history.as_ref()
12002    }
12003
12004    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12005        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12006    }
12007
12008    fn push_to_nav_history(
12009        &mut self,
12010        cursor_anchor: Anchor,
12011        new_position: Option<Point>,
12012        is_deactivate: bool,
12013        cx: &mut Context<Self>,
12014    ) {
12015        if let Some(nav_history) = self.nav_history.as_mut() {
12016            let buffer = self.buffer.read(cx).read(cx);
12017            let cursor_position = cursor_anchor.to_point(&buffer);
12018            let scroll_state = self.scroll_manager.anchor();
12019            let scroll_top_row = scroll_state.top_row(&buffer);
12020            drop(buffer);
12021
12022            if let Some(new_position) = new_position {
12023                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12024                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12025                    return;
12026                }
12027            }
12028
12029            nav_history.push(
12030                Some(NavigationData {
12031                    cursor_anchor,
12032                    cursor_position,
12033                    scroll_anchor: scroll_state,
12034                    scroll_top_row,
12035                }),
12036                cx,
12037            );
12038            cx.emit(EditorEvent::PushedToNavHistory {
12039                anchor: cursor_anchor,
12040                is_deactivate,
12041            })
12042        }
12043    }
12044
12045    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12046        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12047        let buffer = self.buffer.read(cx).snapshot(cx);
12048        let mut selection = self.selections.first::<usize>(cx);
12049        selection.set_head(buffer.len(), SelectionGoal::None);
12050        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12051            s.select(vec![selection]);
12052        });
12053    }
12054
12055    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12056        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12057        let end = self.buffer.read(cx).read(cx).len();
12058        self.change_selections(None, window, cx, |s| {
12059            s.select_ranges(vec![0..end]);
12060        });
12061    }
12062
12063    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12064        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12065        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12066        let mut selections = self.selections.all::<Point>(cx);
12067        let max_point = display_map.buffer_snapshot.max_point();
12068        for selection in &mut selections {
12069            let rows = selection.spanned_rows(true, &display_map);
12070            selection.start = Point::new(rows.start.0, 0);
12071            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12072            selection.reversed = false;
12073        }
12074        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12075            s.select(selections);
12076        });
12077    }
12078
12079    pub fn split_selection_into_lines(
12080        &mut self,
12081        _: &SplitSelectionIntoLines,
12082        window: &mut Window,
12083        cx: &mut Context<Self>,
12084    ) {
12085        let selections = self
12086            .selections
12087            .all::<Point>(cx)
12088            .into_iter()
12089            .map(|selection| selection.start..selection.end)
12090            .collect::<Vec<_>>();
12091        self.unfold_ranges(&selections, true, true, cx);
12092
12093        let mut new_selection_ranges = Vec::new();
12094        {
12095            let buffer = self.buffer.read(cx).read(cx);
12096            for selection in selections {
12097                for row in selection.start.row..selection.end.row {
12098                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12099                    new_selection_ranges.push(cursor..cursor);
12100                }
12101
12102                let is_multiline_selection = selection.start.row != selection.end.row;
12103                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12104                // so this action feels more ergonomic when paired with other selection operations
12105                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12106                if !should_skip_last {
12107                    new_selection_ranges.push(selection.end..selection.end);
12108                }
12109            }
12110        }
12111        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12112            s.select_ranges(new_selection_ranges);
12113        });
12114    }
12115
12116    pub fn add_selection_above(
12117        &mut self,
12118        _: &AddSelectionAbove,
12119        window: &mut Window,
12120        cx: &mut Context<Self>,
12121    ) {
12122        self.add_selection(true, window, cx);
12123    }
12124
12125    pub fn add_selection_below(
12126        &mut self,
12127        _: &AddSelectionBelow,
12128        window: &mut Window,
12129        cx: &mut Context<Self>,
12130    ) {
12131        self.add_selection(false, window, cx);
12132    }
12133
12134    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12135        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12136
12137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12138        let mut selections = self.selections.all::<Point>(cx);
12139        let text_layout_details = self.text_layout_details(window);
12140        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12141            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12142            let range = oldest_selection.display_range(&display_map).sorted();
12143
12144            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12145            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12146            let positions = start_x.min(end_x)..start_x.max(end_x);
12147
12148            selections.clear();
12149            let mut stack = Vec::new();
12150            for row in range.start.row().0..=range.end.row().0 {
12151                if let Some(selection) = self.selections.build_columnar_selection(
12152                    &display_map,
12153                    DisplayRow(row),
12154                    &positions,
12155                    oldest_selection.reversed,
12156                    &text_layout_details,
12157                ) {
12158                    stack.push(selection.id);
12159                    selections.push(selection);
12160                }
12161            }
12162
12163            if above {
12164                stack.reverse();
12165            }
12166
12167            AddSelectionsState { above, stack }
12168        });
12169
12170        let last_added_selection = *state.stack.last().unwrap();
12171        let mut new_selections = Vec::new();
12172        if above == state.above {
12173            let end_row = if above {
12174                DisplayRow(0)
12175            } else {
12176                display_map.max_point().row()
12177            };
12178
12179            'outer: for selection in selections {
12180                if selection.id == last_added_selection {
12181                    let range = selection.display_range(&display_map).sorted();
12182                    debug_assert_eq!(range.start.row(), range.end.row());
12183                    let mut row = range.start.row();
12184                    let positions =
12185                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12186                            px(start)..px(end)
12187                        } else {
12188                            let start_x =
12189                                display_map.x_for_display_point(range.start, &text_layout_details);
12190                            let end_x =
12191                                display_map.x_for_display_point(range.end, &text_layout_details);
12192                            start_x.min(end_x)..start_x.max(end_x)
12193                        };
12194
12195                    while row != end_row {
12196                        if above {
12197                            row.0 -= 1;
12198                        } else {
12199                            row.0 += 1;
12200                        }
12201
12202                        if let Some(new_selection) = self.selections.build_columnar_selection(
12203                            &display_map,
12204                            row,
12205                            &positions,
12206                            selection.reversed,
12207                            &text_layout_details,
12208                        ) {
12209                            state.stack.push(new_selection.id);
12210                            if above {
12211                                new_selections.push(new_selection);
12212                                new_selections.push(selection);
12213                            } else {
12214                                new_selections.push(selection);
12215                                new_selections.push(new_selection);
12216                            }
12217
12218                            continue 'outer;
12219                        }
12220                    }
12221                }
12222
12223                new_selections.push(selection);
12224            }
12225        } else {
12226            new_selections = selections;
12227            new_selections.retain(|s| s.id != last_added_selection);
12228            state.stack.pop();
12229        }
12230
12231        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12232            s.select(new_selections);
12233        });
12234        if state.stack.len() > 1 {
12235            self.add_selections_state = Some(state);
12236        }
12237    }
12238
12239    fn select_match_ranges(
12240        &mut self,
12241        range: Range<usize>,
12242        reversed: bool,
12243        replace_newest: bool,
12244        auto_scroll: Option<Autoscroll>,
12245        window: &mut Window,
12246        cx: &mut Context<Editor>,
12247    ) {
12248        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12249        self.change_selections(auto_scroll, window, cx, |s| {
12250            if replace_newest {
12251                s.delete(s.newest_anchor().id);
12252            }
12253            if reversed {
12254                s.insert_range(range.end..range.start);
12255            } else {
12256                s.insert_range(range);
12257            }
12258        });
12259    }
12260
12261    pub fn select_next_match_internal(
12262        &mut self,
12263        display_map: &DisplaySnapshot,
12264        replace_newest: bool,
12265        autoscroll: Option<Autoscroll>,
12266        window: &mut Window,
12267        cx: &mut Context<Self>,
12268    ) -> Result<()> {
12269        let buffer = &display_map.buffer_snapshot;
12270        let mut selections = self.selections.all::<usize>(cx);
12271        if let Some(mut select_next_state) = self.select_next_state.take() {
12272            let query = &select_next_state.query;
12273            if !select_next_state.done {
12274                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12275                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12276                let mut next_selected_range = None;
12277
12278                let bytes_after_last_selection =
12279                    buffer.bytes_in_range(last_selection.end..buffer.len());
12280                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12281                let query_matches = query
12282                    .stream_find_iter(bytes_after_last_selection)
12283                    .map(|result| (last_selection.end, result))
12284                    .chain(
12285                        query
12286                            .stream_find_iter(bytes_before_first_selection)
12287                            .map(|result| (0, result)),
12288                    );
12289
12290                for (start_offset, query_match) in query_matches {
12291                    let query_match = query_match.unwrap(); // can only fail due to I/O
12292                    let offset_range =
12293                        start_offset + query_match.start()..start_offset + query_match.end();
12294                    let display_range = offset_range.start.to_display_point(display_map)
12295                        ..offset_range.end.to_display_point(display_map);
12296
12297                    if !select_next_state.wordwise
12298                        || (!movement::is_inside_word(display_map, display_range.start)
12299                            && !movement::is_inside_word(display_map, display_range.end))
12300                    {
12301                        // TODO: This is n^2, because we might check all the selections
12302                        if !selections
12303                            .iter()
12304                            .any(|selection| selection.range().overlaps(&offset_range))
12305                        {
12306                            next_selected_range = Some(offset_range);
12307                            break;
12308                        }
12309                    }
12310                }
12311
12312                if let Some(next_selected_range) = next_selected_range {
12313                    self.select_match_ranges(
12314                        next_selected_range,
12315                        last_selection.reversed,
12316                        replace_newest,
12317                        autoscroll,
12318                        window,
12319                        cx,
12320                    );
12321                } else {
12322                    select_next_state.done = true;
12323                }
12324            }
12325
12326            self.select_next_state = Some(select_next_state);
12327        } else {
12328            let mut only_carets = true;
12329            let mut same_text_selected = true;
12330            let mut selected_text = None;
12331
12332            let mut selections_iter = selections.iter().peekable();
12333            while let Some(selection) = selections_iter.next() {
12334                if selection.start != selection.end {
12335                    only_carets = false;
12336                }
12337
12338                if same_text_selected {
12339                    if selected_text.is_none() {
12340                        selected_text =
12341                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12342                    }
12343
12344                    if let Some(next_selection) = selections_iter.peek() {
12345                        if next_selection.range().len() == selection.range().len() {
12346                            let next_selected_text = buffer
12347                                .text_for_range(next_selection.range())
12348                                .collect::<String>();
12349                            if Some(next_selected_text) != selected_text {
12350                                same_text_selected = false;
12351                                selected_text = None;
12352                            }
12353                        } else {
12354                            same_text_selected = false;
12355                            selected_text = None;
12356                        }
12357                    }
12358                }
12359            }
12360
12361            if only_carets {
12362                for selection in &mut selections {
12363                    let word_range = movement::surrounding_word(
12364                        display_map,
12365                        selection.start.to_display_point(display_map),
12366                    );
12367                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12368                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12369                    selection.goal = SelectionGoal::None;
12370                    selection.reversed = false;
12371                    self.select_match_ranges(
12372                        selection.start..selection.end,
12373                        selection.reversed,
12374                        replace_newest,
12375                        autoscroll,
12376                        window,
12377                        cx,
12378                    );
12379                }
12380
12381                if selections.len() == 1 {
12382                    let selection = selections
12383                        .last()
12384                        .expect("ensured that there's only one selection");
12385                    let query = buffer
12386                        .text_for_range(selection.start..selection.end)
12387                        .collect::<String>();
12388                    let is_empty = query.is_empty();
12389                    let select_state = SelectNextState {
12390                        query: AhoCorasick::new(&[query])?,
12391                        wordwise: true,
12392                        done: is_empty,
12393                    };
12394                    self.select_next_state = Some(select_state);
12395                } else {
12396                    self.select_next_state = None;
12397                }
12398            } else if let Some(selected_text) = selected_text {
12399                self.select_next_state = Some(SelectNextState {
12400                    query: AhoCorasick::new(&[selected_text])?,
12401                    wordwise: false,
12402                    done: false,
12403                });
12404                self.select_next_match_internal(
12405                    display_map,
12406                    replace_newest,
12407                    autoscroll,
12408                    window,
12409                    cx,
12410                )?;
12411            }
12412        }
12413        Ok(())
12414    }
12415
12416    pub fn select_all_matches(
12417        &mut self,
12418        _action: &SelectAllMatches,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) -> Result<()> {
12422        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12423
12424        self.push_to_selection_history();
12425        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12426
12427        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12428        let Some(select_next_state) = self.select_next_state.as_mut() else {
12429            return Ok(());
12430        };
12431        if select_next_state.done {
12432            return Ok(());
12433        }
12434
12435        let mut new_selections = Vec::new();
12436
12437        let reversed = self.selections.oldest::<usize>(cx).reversed;
12438        let buffer = &display_map.buffer_snapshot;
12439        let query_matches = select_next_state
12440            .query
12441            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12442
12443        for query_match in query_matches.into_iter() {
12444            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12445            let offset_range = if reversed {
12446                query_match.end()..query_match.start()
12447            } else {
12448                query_match.start()..query_match.end()
12449            };
12450            let display_range = offset_range.start.to_display_point(&display_map)
12451                ..offset_range.end.to_display_point(&display_map);
12452
12453            if !select_next_state.wordwise
12454                || (!movement::is_inside_word(&display_map, display_range.start)
12455                    && !movement::is_inside_word(&display_map, display_range.end))
12456            {
12457                new_selections.push(offset_range.start..offset_range.end);
12458            }
12459        }
12460
12461        select_next_state.done = true;
12462        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12463        self.change_selections(None, window, cx, |selections| {
12464            selections.select_ranges(new_selections)
12465        });
12466
12467        Ok(())
12468    }
12469
12470    pub fn select_next(
12471        &mut self,
12472        action: &SelectNext,
12473        window: &mut Window,
12474        cx: &mut Context<Self>,
12475    ) -> Result<()> {
12476        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12477        self.push_to_selection_history();
12478        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12479        self.select_next_match_internal(
12480            &display_map,
12481            action.replace_newest,
12482            Some(Autoscroll::newest()),
12483            window,
12484            cx,
12485        )?;
12486        Ok(())
12487    }
12488
12489    pub fn select_previous(
12490        &mut self,
12491        action: &SelectPrevious,
12492        window: &mut Window,
12493        cx: &mut Context<Self>,
12494    ) -> Result<()> {
12495        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12496        self.push_to_selection_history();
12497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12498        let buffer = &display_map.buffer_snapshot;
12499        let mut selections = self.selections.all::<usize>(cx);
12500        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12501            let query = &select_prev_state.query;
12502            if !select_prev_state.done {
12503                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12504                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12505                let mut next_selected_range = None;
12506                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12507                let bytes_before_last_selection =
12508                    buffer.reversed_bytes_in_range(0..last_selection.start);
12509                let bytes_after_first_selection =
12510                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12511                let query_matches = query
12512                    .stream_find_iter(bytes_before_last_selection)
12513                    .map(|result| (last_selection.start, result))
12514                    .chain(
12515                        query
12516                            .stream_find_iter(bytes_after_first_selection)
12517                            .map(|result| (buffer.len(), result)),
12518                    );
12519                for (end_offset, query_match) in query_matches {
12520                    let query_match = query_match.unwrap(); // can only fail due to I/O
12521                    let offset_range =
12522                        end_offset - query_match.end()..end_offset - query_match.start();
12523                    let display_range = offset_range.start.to_display_point(&display_map)
12524                        ..offset_range.end.to_display_point(&display_map);
12525
12526                    if !select_prev_state.wordwise
12527                        || (!movement::is_inside_word(&display_map, display_range.start)
12528                            && !movement::is_inside_word(&display_map, display_range.end))
12529                    {
12530                        next_selected_range = Some(offset_range);
12531                        break;
12532                    }
12533                }
12534
12535                if let Some(next_selected_range) = next_selected_range {
12536                    self.select_match_ranges(
12537                        next_selected_range,
12538                        last_selection.reversed,
12539                        action.replace_newest,
12540                        Some(Autoscroll::newest()),
12541                        window,
12542                        cx,
12543                    );
12544                } else {
12545                    select_prev_state.done = true;
12546                }
12547            }
12548
12549            self.select_prev_state = Some(select_prev_state);
12550        } else {
12551            let mut only_carets = true;
12552            let mut same_text_selected = true;
12553            let mut selected_text = None;
12554
12555            let mut selections_iter = selections.iter().peekable();
12556            while let Some(selection) = selections_iter.next() {
12557                if selection.start != selection.end {
12558                    only_carets = false;
12559                }
12560
12561                if same_text_selected {
12562                    if selected_text.is_none() {
12563                        selected_text =
12564                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12565                    }
12566
12567                    if let Some(next_selection) = selections_iter.peek() {
12568                        if next_selection.range().len() == selection.range().len() {
12569                            let next_selected_text = buffer
12570                                .text_for_range(next_selection.range())
12571                                .collect::<String>();
12572                            if Some(next_selected_text) != selected_text {
12573                                same_text_selected = false;
12574                                selected_text = None;
12575                            }
12576                        } else {
12577                            same_text_selected = false;
12578                            selected_text = None;
12579                        }
12580                    }
12581                }
12582            }
12583
12584            if only_carets {
12585                for selection in &mut selections {
12586                    let word_range = movement::surrounding_word(
12587                        &display_map,
12588                        selection.start.to_display_point(&display_map),
12589                    );
12590                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12591                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12592                    selection.goal = SelectionGoal::None;
12593                    selection.reversed = false;
12594                    self.select_match_ranges(
12595                        selection.start..selection.end,
12596                        selection.reversed,
12597                        action.replace_newest,
12598                        Some(Autoscroll::newest()),
12599                        window,
12600                        cx,
12601                    );
12602                }
12603                if selections.len() == 1 {
12604                    let selection = selections
12605                        .last()
12606                        .expect("ensured that there's only one selection");
12607                    let query = buffer
12608                        .text_for_range(selection.start..selection.end)
12609                        .collect::<String>();
12610                    let is_empty = query.is_empty();
12611                    let select_state = SelectNextState {
12612                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12613                        wordwise: true,
12614                        done: is_empty,
12615                    };
12616                    self.select_prev_state = Some(select_state);
12617                } else {
12618                    self.select_prev_state = None;
12619                }
12620            } else if let Some(selected_text) = selected_text {
12621                self.select_prev_state = Some(SelectNextState {
12622                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12623                    wordwise: false,
12624                    done: false,
12625                });
12626                self.select_previous(action, window, cx)?;
12627            }
12628        }
12629        Ok(())
12630    }
12631
12632    pub fn find_next_match(
12633        &mut self,
12634        _: &FindNextMatch,
12635        window: &mut Window,
12636        cx: &mut Context<Self>,
12637    ) -> Result<()> {
12638        let selections = self.selections.disjoint_anchors();
12639        match selections.first() {
12640            Some(first) if selections.len() >= 2 => {
12641                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12642                    s.select_ranges([first.range()]);
12643                });
12644            }
12645            _ => self.select_next(
12646                &SelectNext {
12647                    replace_newest: true,
12648                },
12649                window,
12650                cx,
12651            )?,
12652        }
12653        Ok(())
12654    }
12655
12656    pub fn find_previous_match(
12657        &mut self,
12658        _: &FindPreviousMatch,
12659        window: &mut Window,
12660        cx: &mut Context<Self>,
12661    ) -> Result<()> {
12662        let selections = self.selections.disjoint_anchors();
12663        match selections.last() {
12664            Some(last) if selections.len() >= 2 => {
12665                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12666                    s.select_ranges([last.range()]);
12667                });
12668            }
12669            _ => self.select_previous(
12670                &SelectPrevious {
12671                    replace_newest: true,
12672                },
12673                window,
12674                cx,
12675            )?,
12676        }
12677        Ok(())
12678    }
12679
12680    pub fn toggle_comments(
12681        &mut self,
12682        action: &ToggleComments,
12683        window: &mut Window,
12684        cx: &mut Context<Self>,
12685    ) {
12686        if self.read_only(cx) {
12687            return;
12688        }
12689        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12690        let text_layout_details = &self.text_layout_details(window);
12691        self.transact(window, cx, |this, window, cx| {
12692            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12693            let mut edits = Vec::new();
12694            let mut selection_edit_ranges = Vec::new();
12695            let mut last_toggled_row = None;
12696            let snapshot = this.buffer.read(cx).read(cx);
12697            let empty_str: Arc<str> = Arc::default();
12698            let mut suffixes_inserted = Vec::new();
12699            let ignore_indent = action.ignore_indent;
12700
12701            fn comment_prefix_range(
12702                snapshot: &MultiBufferSnapshot,
12703                row: MultiBufferRow,
12704                comment_prefix: &str,
12705                comment_prefix_whitespace: &str,
12706                ignore_indent: bool,
12707            ) -> Range<Point> {
12708                let indent_size = if ignore_indent {
12709                    0
12710                } else {
12711                    snapshot.indent_size_for_line(row).len
12712                };
12713
12714                let start = Point::new(row.0, indent_size);
12715
12716                let mut line_bytes = snapshot
12717                    .bytes_in_range(start..snapshot.max_point())
12718                    .flatten()
12719                    .copied();
12720
12721                // If this line currently begins with the line comment prefix, then record
12722                // the range containing the prefix.
12723                if line_bytes
12724                    .by_ref()
12725                    .take(comment_prefix.len())
12726                    .eq(comment_prefix.bytes())
12727                {
12728                    // Include any whitespace that matches the comment prefix.
12729                    let matching_whitespace_len = line_bytes
12730                        .zip(comment_prefix_whitespace.bytes())
12731                        .take_while(|(a, b)| a == b)
12732                        .count() as u32;
12733                    let end = Point::new(
12734                        start.row,
12735                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12736                    );
12737                    start..end
12738                } else {
12739                    start..start
12740                }
12741            }
12742
12743            fn comment_suffix_range(
12744                snapshot: &MultiBufferSnapshot,
12745                row: MultiBufferRow,
12746                comment_suffix: &str,
12747                comment_suffix_has_leading_space: bool,
12748            ) -> Range<Point> {
12749                let end = Point::new(row.0, snapshot.line_len(row));
12750                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12751
12752                let mut line_end_bytes = snapshot
12753                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12754                    .flatten()
12755                    .copied();
12756
12757                let leading_space_len = if suffix_start_column > 0
12758                    && line_end_bytes.next() == Some(b' ')
12759                    && comment_suffix_has_leading_space
12760                {
12761                    1
12762                } else {
12763                    0
12764                };
12765
12766                // If this line currently begins with the line comment prefix, then record
12767                // the range containing the prefix.
12768                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12769                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12770                    start..end
12771                } else {
12772                    end..end
12773                }
12774            }
12775
12776            // TODO: Handle selections that cross excerpts
12777            for selection in &mut selections {
12778                let start_column = snapshot
12779                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12780                    .len;
12781                let language = if let Some(language) =
12782                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12783                {
12784                    language
12785                } else {
12786                    continue;
12787                };
12788
12789                selection_edit_ranges.clear();
12790
12791                // If multiple selections contain a given row, avoid processing that
12792                // row more than once.
12793                let mut start_row = MultiBufferRow(selection.start.row);
12794                if last_toggled_row == Some(start_row) {
12795                    start_row = start_row.next_row();
12796                }
12797                let end_row =
12798                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12799                        MultiBufferRow(selection.end.row - 1)
12800                    } else {
12801                        MultiBufferRow(selection.end.row)
12802                    };
12803                last_toggled_row = Some(end_row);
12804
12805                if start_row > end_row {
12806                    continue;
12807                }
12808
12809                // If the language has line comments, toggle those.
12810                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12811
12812                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12813                if ignore_indent {
12814                    full_comment_prefixes = full_comment_prefixes
12815                        .into_iter()
12816                        .map(|s| Arc::from(s.trim_end()))
12817                        .collect();
12818                }
12819
12820                if !full_comment_prefixes.is_empty() {
12821                    let first_prefix = full_comment_prefixes
12822                        .first()
12823                        .expect("prefixes is non-empty");
12824                    let prefix_trimmed_lengths = full_comment_prefixes
12825                        .iter()
12826                        .map(|p| p.trim_end_matches(' ').len())
12827                        .collect::<SmallVec<[usize; 4]>>();
12828
12829                    let mut all_selection_lines_are_comments = true;
12830
12831                    for row in start_row.0..=end_row.0 {
12832                        let row = MultiBufferRow(row);
12833                        if start_row < end_row && snapshot.is_line_blank(row) {
12834                            continue;
12835                        }
12836
12837                        let prefix_range = full_comment_prefixes
12838                            .iter()
12839                            .zip(prefix_trimmed_lengths.iter().copied())
12840                            .map(|(prefix, trimmed_prefix_len)| {
12841                                comment_prefix_range(
12842                                    snapshot.deref(),
12843                                    row,
12844                                    &prefix[..trimmed_prefix_len],
12845                                    &prefix[trimmed_prefix_len..],
12846                                    ignore_indent,
12847                                )
12848                            })
12849                            .max_by_key(|range| range.end.column - range.start.column)
12850                            .expect("prefixes is non-empty");
12851
12852                        if prefix_range.is_empty() {
12853                            all_selection_lines_are_comments = false;
12854                        }
12855
12856                        selection_edit_ranges.push(prefix_range);
12857                    }
12858
12859                    if all_selection_lines_are_comments {
12860                        edits.extend(
12861                            selection_edit_ranges
12862                                .iter()
12863                                .cloned()
12864                                .map(|range| (range, empty_str.clone())),
12865                        );
12866                    } else {
12867                        let min_column = selection_edit_ranges
12868                            .iter()
12869                            .map(|range| range.start.column)
12870                            .min()
12871                            .unwrap_or(0);
12872                        edits.extend(selection_edit_ranges.iter().map(|range| {
12873                            let position = Point::new(range.start.row, min_column);
12874                            (position..position, first_prefix.clone())
12875                        }));
12876                    }
12877                } else if let Some((full_comment_prefix, comment_suffix)) =
12878                    language.block_comment_delimiters()
12879                {
12880                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
12881                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
12882                    let prefix_range = comment_prefix_range(
12883                        snapshot.deref(),
12884                        start_row,
12885                        comment_prefix,
12886                        comment_prefix_whitespace,
12887                        ignore_indent,
12888                    );
12889                    let suffix_range = comment_suffix_range(
12890                        snapshot.deref(),
12891                        end_row,
12892                        comment_suffix.trim_start_matches(' '),
12893                        comment_suffix.starts_with(' '),
12894                    );
12895
12896                    if prefix_range.is_empty() || suffix_range.is_empty() {
12897                        edits.push((
12898                            prefix_range.start..prefix_range.start,
12899                            full_comment_prefix.clone(),
12900                        ));
12901                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
12902                        suffixes_inserted.push((end_row, comment_suffix.len()));
12903                    } else {
12904                        edits.push((prefix_range, empty_str.clone()));
12905                        edits.push((suffix_range, empty_str.clone()));
12906                    }
12907                } else {
12908                    continue;
12909                }
12910            }
12911
12912            drop(snapshot);
12913            this.buffer.update(cx, |buffer, cx| {
12914                buffer.edit(edits, None, cx);
12915            });
12916
12917            // Adjust selections so that they end before any comment suffixes that
12918            // were inserted.
12919            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
12920            let mut selections = this.selections.all::<Point>(cx);
12921            let snapshot = this.buffer.read(cx).read(cx);
12922            for selection in &mut selections {
12923                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
12924                    match row.cmp(&MultiBufferRow(selection.end.row)) {
12925                        Ordering::Less => {
12926                            suffixes_inserted.next();
12927                            continue;
12928                        }
12929                        Ordering::Greater => break,
12930                        Ordering::Equal => {
12931                            if selection.end.column == snapshot.line_len(row) {
12932                                if selection.is_empty() {
12933                                    selection.start.column -= suffix_len as u32;
12934                                }
12935                                selection.end.column -= suffix_len as u32;
12936                            }
12937                            break;
12938                        }
12939                    }
12940                }
12941            }
12942
12943            drop(snapshot);
12944            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12945                s.select(selections)
12946            });
12947
12948            let selections = this.selections.all::<Point>(cx);
12949            let selections_on_single_row = selections.windows(2).all(|selections| {
12950                selections[0].start.row == selections[1].start.row
12951                    && selections[0].end.row == selections[1].end.row
12952                    && selections[0].start.row == selections[0].end.row
12953            });
12954            let selections_selecting = selections
12955                .iter()
12956                .any(|selection| selection.start != selection.end);
12957            let advance_downwards = action.advance_downwards
12958                && selections_on_single_row
12959                && !selections_selecting
12960                && !matches!(this.mode, EditorMode::SingleLine { .. });
12961
12962            if advance_downwards {
12963                let snapshot = this.buffer.read(cx).snapshot(cx);
12964
12965                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12966                    s.move_cursors_with(|display_snapshot, display_point, _| {
12967                        let mut point = display_point.to_point(display_snapshot);
12968                        point.row += 1;
12969                        point = snapshot.clip_point(point, Bias::Left);
12970                        let display_point = point.to_display_point(display_snapshot);
12971                        let goal = SelectionGoal::HorizontalPosition(
12972                            display_snapshot
12973                                .x_for_display_point(display_point, text_layout_details)
12974                                .into(),
12975                        );
12976                        (display_point, goal)
12977                    })
12978                });
12979            }
12980        });
12981    }
12982
12983    pub fn select_enclosing_symbol(
12984        &mut self,
12985        _: &SelectEnclosingSymbol,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12990
12991        let buffer = self.buffer.read(cx).snapshot(cx);
12992        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
12993
12994        fn update_selection(
12995            selection: &Selection<usize>,
12996            buffer_snap: &MultiBufferSnapshot,
12997        ) -> Option<Selection<usize>> {
12998            let cursor = selection.head();
12999            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13000            for symbol in symbols.iter().rev() {
13001                let start = symbol.range.start.to_offset(buffer_snap);
13002                let end = symbol.range.end.to_offset(buffer_snap);
13003                let new_range = start..end;
13004                if start < selection.start || end > selection.end {
13005                    return Some(Selection {
13006                        id: selection.id,
13007                        start: new_range.start,
13008                        end: new_range.end,
13009                        goal: SelectionGoal::None,
13010                        reversed: selection.reversed,
13011                    });
13012                }
13013            }
13014            None
13015        }
13016
13017        let mut selected_larger_symbol = false;
13018        let new_selections = old_selections
13019            .iter()
13020            .map(|selection| match update_selection(selection, &buffer) {
13021                Some(new_selection) => {
13022                    if new_selection.range() != selection.range() {
13023                        selected_larger_symbol = true;
13024                    }
13025                    new_selection
13026                }
13027                None => selection.clone(),
13028            })
13029            .collect::<Vec<_>>();
13030
13031        if selected_larger_symbol {
13032            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13033                s.select(new_selections);
13034            });
13035        }
13036    }
13037
13038    pub fn select_larger_syntax_node(
13039        &mut self,
13040        _: &SelectLargerSyntaxNode,
13041        window: &mut Window,
13042        cx: &mut Context<Self>,
13043    ) {
13044        let Some(visible_row_count) = self.visible_row_count() else {
13045            return;
13046        };
13047        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13048        if old_selections.is_empty() {
13049            return;
13050        }
13051
13052        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13053
13054        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13055        let buffer = self.buffer.read(cx).snapshot(cx);
13056
13057        let mut selected_larger_node = false;
13058        let mut new_selections = old_selections
13059            .iter()
13060            .map(|selection| {
13061                let old_range = selection.start..selection.end;
13062
13063                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13064                    // manually select word at selection
13065                    if ["string_content", "inline"].contains(&node.kind()) {
13066                        let word_range = {
13067                            let display_point = buffer
13068                                .offset_to_point(old_range.start)
13069                                .to_display_point(&display_map);
13070                            let Range { start, end } =
13071                                movement::surrounding_word(&display_map, display_point);
13072                            start.to_point(&display_map).to_offset(&buffer)
13073                                ..end.to_point(&display_map).to_offset(&buffer)
13074                        };
13075                        // ignore if word is already selected
13076                        if !word_range.is_empty() && old_range != word_range {
13077                            let last_word_range = {
13078                                let display_point = buffer
13079                                    .offset_to_point(old_range.end)
13080                                    .to_display_point(&display_map);
13081                                let Range { start, end } =
13082                                    movement::surrounding_word(&display_map, display_point);
13083                                start.to_point(&display_map).to_offset(&buffer)
13084                                    ..end.to_point(&display_map).to_offset(&buffer)
13085                            };
13086                            // only select word if start and end point belongs to same word
13087                            if word_range == last_word_range {
13088                                selected_larger_node = true;
13089                                return Selection {
13090                                    id: selection.id,
13091                                    start: word_range.start,
13092                                    end: word_range.end,
13093                                    goal: SelectionGoal::None,
13094                                    reversed: selection.reversed,
13095                                };
13096                            }
13097                        }
13098                    }
13099                }
13100
13101                let mut new_range = old_range.clone();
13102                while let Some((_node, containing_range)) =
13103                    buffer.syntax_ancestor(new_range.clone())
13104                {
13105                    new_range = match containing_range {
13106                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13107                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13108                    };
13109                    if !display_map.intersects_fold(new_range.start)
13110                        && !display_map.intersects_fold(new_range.end)
13111                    {
13112                        break;
13113                    }
13114                }
13115
13116                selected_larger_node |= new_range != old_range;
13117                Selection {
13118                    id: selection.id,
13119                    start: new_range.start,
13120                    end: new_range.end,
13121                    goal: SelectionGoal::None,
13122                    reversed: selection.reversed,
13123                }
13124            })
13125            .collect::<Vec<_>>();
13126
13127        if !selected_larger_node {
13128            return; // don't put this call in the history
13129        }
13130
13131        // scroll based on transformation done to the last selection created by the user
13132        let (last_old, last_new) = old_selections
13133            .last()
13134            .zip(new_selections.last().cloned())
13135            .expect("old_selections isn't empty");
13136
13137        // revert selection
13138        let is_selection_reversed = {
13139            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13140            new_selections.last_mut().expect("checked above").reversed =
13141                should_newest_selection_be_reversed;
13142            should_newest_selection_be_reversed
13143        };
13144
13145        if selected_larger_node {
13146            self.select_syntax_node_history.disable_clearing = true;
13147            self.change_selections(None, window, cx, |s| {
13148                s.select(new_selections.clone());
13149            });
13150            self.select_syntax_node_history.disable_clearing = false;
13151        }
13152
13153        let start_row = last_new.start.to_display_point(&display_map).row().0;
13154        let end_row = last_new.end.to_display_point(&display_map).row().0;
13155        let selection_height = end_row - start_row + 1;
13156        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13157
13158        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13159        let scroll_behavior = if fits_on_the_screen {
13160            self.request_autoscroll(Autoscroll::fit(), cx);
13161            SelectSyntaxNodeScrollBehavior::FitSelection
13162        } else if is_selection_reversed {
13163            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13164            SelectSyntaxNodeScrollBehavior::CursorTop
13165        } else {
13166            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13167            SelectSyntaxNodeScrollBehavior::CursorBottom
13168        };
13169
13170        self.select_syntax_node_history.push((
13171            old_selections,
13172            scroll_behavior,
13173            is_selection_reversed,
13174        ));
13175    }
13176
13177    pub fn select_smaller_syntax_node(
13178        &mut self,
13179        _: &SelectSmallerSyntaxNode,
13180        window: &mut Window,
13181        cx: &mut Context<Self>,
13182    ) {
13183        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13184
13185        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13186            self.select_syntax_node_history.pop()
13187        {
13188            if let Some(selection) = selections.last_mut() {
13189                selection.reversed = is_selection_reversed;
13190            }
13191
13192            self.select_syntax_node_history.disable_clearing = true;
13193            self.change_selections(None, window, cx, |s| {
13194                s.select(selections.to_vec());
13195            });
13196            self.select_syntax_node_history.disable_clearing = false;
13197
13198            match scroll_behavior {
13199                SelectSyntaxNodeScrollBehavior::CursorTop => {
13200                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13201                }
13202                SelectSyntaxNodeScrollBehavior::FitSelection => {
13203                    self.request_autoscroll(Autoscroll::fit(), cx);
13204                }
13205                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13206                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13207                }
13208            }
13209        }
13210    }
13211
13212    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13213        if !EditorSettings::get_global(cx).gutter.runnables {
13214            self.clear_tasks();
13215            return Task::ready(());
13216        }
13217        let project = self.project.as_ref().map(Entity::downgrade);
13218        let task_sources = self.lsp_task_sources(cx);
13219        cx.spawn_in(window, async move |editor, cx| {
13220            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13221            let Some(project) = project.and_then(|p| p.upgrade()) else {
13222                return;
13223            };
13224            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13225                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13226            }) else {
13227                return;
13228            };
13229
13230            let hide_runnables = project
13231                .update(cx, |project, cx| {
13232                    // Do not display any test indicators in non-dev server remote projects.
13233                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13234                })
13235                .unwrap_or(true);
13236            if hide_runnables {
13237                return;
13238            }
13239            let new_rows =
13240                cx.background_spawn({
13241                    let snapshot = display_snapshot.clone();
13242                    async move {
13243                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13244                    }
13245                })
13246                    .await;
13247            let Ok(lsp_tasks) =
13248                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13249            else {
13250                return;
13251            };
13252            let lsp_tasks = lsp_tasks.await;
13253
13254            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13255                lsp_tasks
13256                    .into_iter()
13257                    .flat_map(|(kind, tasks)| {
13258                        tasks.into_iter().filter_map(move |(location, task)| {
13259                            Some((kind.clone(), location?, task))
13260                        })
13261                    })
13262                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13263                        let buffer = location.target.buffer;
13264                        let buffer_snapshot = buffer.read(cx).snapshot();
13265                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13266                            |(excerpt_id, snapshot, _)| {
13267                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13268                                    display_snapshot
13269                                        .buffer_snapshot
13270                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13271                                } else {
13272                                    None
13273                                }
13274                            },
13275                        );
13276                        if let Some(offset) = offset {
13277                            let task_buffer_range =
13278                                location.target.range.to_point(&buffer_snapshot);
13279                            let context_buffer_range =
13280                                task_buffer_range.to_offset(&buffer_snapshot);
13281                            let context_range = BufferOffset(context_buffer_range.start)
13282                                ..BufferOffset(context_buffer_range.end);
13283
13284                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13285                                .or_insert_with(|| RunnableTasks {
13286                                    templates: Vec::new(),
13287                                    offset,
13288                                    column: task_buffer_range.start.column,
13289                                    extra_variables: HashMap::default(),
13290                                    context_range,
13291                                })
13292                                .templates
13293                                .push((kind, task.original_task().clone()));
13294                        }
13295
13296                        acc
13297                    })
13298            }) else {
13299                return;
13300            };
13301
13302            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13303            editor
13304                .update(cx, |editor, _| {
13305                    editor.clear_tasks();
13306                    for (key, mut value) in rows {
13307                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13308                            value.templates.extend(lsp_tasks.templates);
13309                        }
13310
13311                        editor.insert_tasks(key, value);
13312                    }
13313                    for (key, value) in lsp_tasks_by_rows {
13314                        editor.insert_tasks(key, value);
13315                    }
13316                })
13317                .ok();
13318        })
13319    }
13320    fn fetch_runnable_ranges(
13321        snapshot: &DisplaySnapshot,
13322        range: Range<Anchor>,
13323    ) -> Vec<language::RunnableRange> {
13324        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13325    }
13326
13327    fn runnable_rows(
13328        project: Entity<Project>,
13329        snapshot: DisplaySnapshot,
13330        runnable_ranges: Vec<RunnableRange>,
13331        mut cx: AsyncWindowContext,
13332    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13333        runnable_ranges
13334            .into_iter()
13335            .filter_map(|mut runnable| {
13336                let tasks = cx
13337                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13338                    .ok()?;
13339                if tasks.is_empty() {
13340                    return None;
13341                }
13342
13343                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13344
13345                let row = snapshot
13346                    .buffer_snapshot
13347                    .buffer_line_for_row(MultiBufferRow(point.row))?
13348                    .1
13349                    .start
13350                    .row;
13351
13352                let context_range =
13353                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13354                Some((
13355                    (runnable.buffer_id, row),
13356                    RunnableTasks {
13357                        templates: tasks,
13358                        offset: snapshot
13359                            .buffer_snapshot
13360                            .anchor_before(runnable.run_range.start),
13361                        context_range,
13362                        column: point.column,
13363                        extra_variables: runnable.extra_captures,
13364                    },
13365                ))
13366            })
13367            .collect()
13368    }
13369
13370    fn templates_with_tags(
13371        project: &Entity<Project>,
13372        runnable: &mut Runnable,
13373        cx: &mut App,
13374    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13375        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13376            let (worktree_id, file) = project
13377                .buffer_for_id(runnable.buffer, cx)
13378                .and_then(|buffer| buffer.read(cx).file())
13379                .map(|file| (file.worktree_id(cx), file.clone()))
13380                .unzip();
13381
13382            (
13383                project.task_store().read(cx).task_inventory().cloned(),
13384                worktree_id,
13385                file,
13386            )
13387        });
13388
13389        let mut templates_with_tags = mem::take(&mut runnable.tags)
13390            .into_iter()
13391            .flat_map(|RunnableTag(tag)| {
13392                inventory
13393                    .as_ref()
13394                    .into_iter()
13395                    .flat_map(|inventory| {
13396                        inventory.read(cx).list_tasks(
13397                            file.clone(),
13398                            Some(runnable.language.clone()),
13399                            worktree_id,
13400                            cx,
13401                        )
13402                    })
13403                    .filter(move |(_, template)| {
13404                        template.tags.iter().any(|source_tag| source_tag == &tag)
13405                    })
13406            })
13407            .sorted_by_key(|(kind, _)| kind.to_owned())
13408            .collect::<Vec<_>>();
13409        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13410            // Strongest source wins; if we have worktree tag binding, prefer that to
13411            // global and language bindings;
13412            // if we have a global binding, prefer that to language binding.
13413            let first_mismatch = templates_with_tags
13414                .iter()
13415                .position(|(tag_source, _)| tag_source != leading_tag_source);
13416            if let Some(index) = first_mismatch {
13417                templates_with_tags.truncate(index);
13418            }
13419        }
13420
13421        templates_with_tags
13422    }
13423
13424    pub fn move_to_enclosing_bracket(
13425        &mut self,
13426        _: &MoveToEnclosingBracket,
13427        window: &mut Window,
13428        cx: &mut Context<Self>,
13429    ) {
13430        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13431        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13432            s.move_offsets_with(|snapshot, selection| {
13433                let Some(enclosing_bracket_ranges) =
13434                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13435                else {
13436                    return;
13437                };
13438
13439                let mut best_length = usize::MAX;
13440                let mut best_inside = false;
13441                let mut best_in_bracket_range = false;
13442                let mut best_destination = None;
13443                for (open, close) in enclosing_bracket_ranges {
13444                    let close = close.to_inclusive();
13445                    let length = close.end() - open.start;
13446                    let inside = selection.start >= open.end && selection.end <= *close.start();
13447                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13448                        || close.contains(&selection.head());
13449
13450                    // If best is next to a bracket and current isn't, skip
13451                    if !in_bracket_range && best_in_bracket_range {
13452                        continue;
13453                    }
13454
13455                    // Prefer smaller lengths unless best is inside and current isn't
13456                    if length > best_length && (best_inside || !inside) {
13457                        continue;
13458                    }
13459
13460                    best_length = length;
13461                    best_inside = inside;
13462                    best_in_bracket_range = in_bracket_range;
13463                    best_destination = Some(
13464                        if close.contains(&selection.start) && close.contains(&selection.end) {
13465                            if inside { open.end } else { open.start }
13466                        } else if inside {
13467                            *close.start()
13468                        } else {
13469                            *close.end()
13470                        },
13471                    );
13472                }
13473
13474                if let Some(destination) = best_destination {
13475                    selection.collapse_to(destination, SelectionGoal::None);
13476                }
13477            })
13478        });
13479    }
13480
13481    pub fn undo_selection(
13482        &mut self,
13483        _: &UndoSelection,
13484        window: &mut Window,
13485        cx: &mut Context<Self>,
13486    ) {
13487        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13488        self.end_selection(window, cx);
13489        self.selection_history.mode = SelectionHistoryMode::Undoing;
13490        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13491            self.change_selections(None, window, cx, |s| {
13492                s.select_anchors(entry.selections.to_vec())
13493            });
13494            self.select_next_state = entry.select_next_state;
13495            self.select_prev_state = entry.select_prev_state;
13496            self.add_selections_state = entry.add_selections_state;
13497            self.request_autoscroll(Autoscroll::newest(), cx);
13498        }
13499        self.selection_history.mode = SelectionHistoryMode::Normal;
13500    }
13501
13502    pub fn redo_selection(
13503        &mut self,
13504        _: &RedoSelection,
13505        window: &mut Window,
13506        cx: &mut Context<Self>,
13507    ) {
13508        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13509        self.end_selection(window, cx);
13510        self.selection_history.mode = SelectionHistoryMode::Redoing;
13511        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13512            self.change_selections(None, window, cx, |s| {
13513                s.select_anchors(entry.selections.to_vec())
13514            });
13515            self.select_next_state = entry.select_next_state;
13516            self.select_prev_state = entry.select_prev_state;
13517            self.add_selections_state = entry.add_selections_state;
13518            self.request_autoscroll(Autoscroll::newest(), cx);
13519        }
13520        self.selection_history.mode = SelectionHistoryMode::Normal;
13521    }
13522
13523    pub fn expand_excerpts(
13524        &mut self,
13525        action: &ExpandExcerpts,
13526        _: &mut Window,
13527        cx: &mut Context<Self>,
13528    ) {
13529        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13530    }
13531
13532    pub fn expand_excerpts_down(
13533        &mut self,
13534        action: &ExpandExcerptsDown,
13535        _: &mut Window,
13536        cx: &mut Context<Self>,
13537    ) {
13538        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13539    }
13540
13541    pub fn expand_excerpts_up(
13542        &mut self,
13543        action: &ExpandExcerptsUp,
13544        _: &mut Window,
13545        cx: &mut Context<Self>,
13546    ) {
13547        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13548    }
13549
13550    pub fn expand_excerpts_for_direction(
13551        &mut self,
13552        lines: u32,
13553        direction: ExpandExcerptDirection,
13554
13555        cx: &mut Context<Self>,
13556    ) {
13557        let selections = self.selections.disjoint_anchors();
13558
13559        let lines = if lines == 0 {
13560            EditorSettings::get_global(cx).expand_excerpt_lines
13561        } else {
13562            lines
13563        };
13564
13565        self.buffer.update(cx, |buffer, cx| {
13566            let snapshot = buffer.snapshot(cx);
13567            let mut excerpt_ids = selections
13568                .iter()
13569                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13570                .collect::<Vec<_>>();
13571            excerpt_ids.sort();
13572            excerpt_ids.dedup();
13573            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13574        })
13575    }
13576
13577    pub fn expand_excerpt(
13578        &mut self,
13579        excerpt: ExcerptId,
13580        direction: ExpandExcerptDirection,
13581        window: &mut Window,
13582        cx: &mut Context<Self>,
13583    ) {
13584        let current_scroll_position = self.scroll_position(cx);
13585        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13586        let mut should_scroll_up = false;
13587
13588        if direction == ExpandExcerptDirection::Down {
13589            let multi_buffer = self.buffer.read(cx);
13590            let snapshot = multi_buffer.snapshot(cx);
13591            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13592                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13593                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13594                        let buffer_snapshot = buffer.read(cx).snapshot();
13595                        let excerpt_end_row =
13596                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13597                        let last_row = buffer_snapshot.max_point().row;
13598                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13599                        should_scroll_up = lines_below >= lines_to_expand;
13600                    }
13601                }
13602            }
13603        }
13604
13605        self.buffer.update(cx, |buffer, cx| {
13606            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13607        });
13608
13609        if should_scroll_up {
13610            let new_scroll_position =
13611                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13612            self.set_scroll_position(new_scroll_position, window, cx);
13613        }
13614    }
13615
13616    pub fn go_to_singleton_buffer_point(
13617        &mut self,
13618        point: Point,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        self.go_to_singleton_buffer_range(point..point, window, cx);
13623    }
13624
13625    pub fn go_to_singleton_buffer_range(
13626        &mut self,
13627        range: Range<Point>,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        let multibuffer = self.buffer().read(cx);
13632        let Some(buffer) = multibuffer.as_singleton() else {
13633            return;
13634        };
13635        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13636            return;
13637        };
13638        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13639            return;
13640        };
13641        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13642            s.select_anchor_ranges([start..end])
13643        });
13644    }
13645
13646    pub fn go_to_diagnostic(
13647        &mut self,
13648        _: &GoToDiagnostic,
13649        window: &mut Window,
13650        cx: &mut Context<Self>,
13651    ) {
13652        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13653        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13654    }
13655
13656    pub fn go_to_prev_diagnostic(
13657        &mut self,
13658        _: &GoToPreviousDiagnostic,
13659        window: &mut Window,
13660        cx: &mut Context<Self>,
13661    ) {
13662        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13663        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13664    }
13665
13666    pub fn go_to_diagnostic_impl(
13667        &mut self,
13668        direction: Direction,
13669        window: &mut Window,
13670        cx: &mut Context<Self>,
13671    ) {
13672        let buffer = self.buffer.read(cx).snapshot(cx);
13673        let selection = self.selections.newest::<usize>(cx);
13674
13675        let mut active_group_id = None;
13676        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13677            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13678                active_group_id = Some(active_group.group_id);
13679            }
13680        }
13681
13682        fn filtered(
13683            snapshot: EditorSnapshot,
13684            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13685        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13686            diagnostics
13687                .filter(|entry| entry.range.start != entry.range.end)
13688                .filter(|entry| !entry.diagnostic.is_unnecessary)
13689                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13690        }
13691
13692        let snapshot = self.snapshot(window, cx);
13693        let before = filtered(
13694            snapshot.clone(),
13695            buffer
13696                .diagnostics_in_range(0..selection.start)
13697                .filter(|entry| entry.range.start <= selection.start),
13698        );
13699        let after = filtered(
13700            snapshot,
13701            buffer
13702                .diagnostics_in_range(selection.start..buffer.len())
13703                .filter(|entry| entry.range.start >= selection.start),
13704        );
13705
13706        let mut found: Option<DiagnosticEntry<usize>> = None;
13707        if direction == Direction::Prev {
13708            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13709            {
13710                for diagnostic in prev_diagnostics.into_iter().rev() {
13711                    if diagnostic.range.start != selection.start
13712                        || active_group_id
13713                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13714                    {
13715                        found = Some(diagnostic);
13716                        break 'outer;
13717                    }
13718                }
13719            }
13720        } else {
13721            for diagnostic in after.chain(before) {
13722                if diagnostic.range.start != selection.start
13723                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13724                {
13725                    found = Some(diagnostic);
13726                    break;
13727                }
13728            }
13729        }
13730        let Some(next_diagnostic) = found else {
13731            return;
13732        };
13733
13734        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13735            return;
13736        };
13737        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13738            s.select_ranges(vec![
13739                next_diagnostic.range.start..next_diagnostic.range.start,
13740            ])
13741        });
13742        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13743        self.refresh_inline_completion(false, true, window, cx);
13744    }
13745
13746    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13747        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13748        let snapshot = self.snapshot(window, cx);
13749        let selection = self.selections.newest::<Point>(cx);
13750        self.go_to_hunk_before_or_after_position(
13751            &snapshot,
13752            selection.head(),
13753            Direction::Next,
13754            window,
13755            cx,
13756        );
13757    }
13758
13759    pub fn go_to_hunk_before_or_after_position(
13760        &mut self,
13761        snapshot: &EditorSnapshot,
13762        position: Point,
13763        direction: Direction,
13764        window: &mut Window,
13765        cx: &mut Context<Editor>,
13766    ) {
13767        let row = if direction == Direction::Next {
13768            self.hunk_after_position(snapshot, position)
13769                .map(|hunk| hunk.row_range.start)
13770        } else {
13771            self.hunk_before_position(snapshot, position)
13772        };
13773
13774        if let Some(row) = row {
13775            let destination = Point::new(row.0, 0);
13776            let autoscroll = Autoscroll::center();
13777
13778            self.unfold_ranges(&[destination..destination], false, false, cx);
13779            self.change_selections(Some(autoscroll), window, cx, |s| {
13780                s.select_ranges([destination..destination]);
13781            });
13782        }
13783    }
13784
13785    fn hunk_after_position(
13786        &mut self,
13787        snapshot: &EditorSnapshot,
13788        position: Point,
13789    ) -> Option<MultiBufferDiffHunk> {
13790        snapshot
13791            .buffer_snapshot
13792            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13793            .find(|hunk| hunk.row_range.start.0 > position.row)
13794            .or_else(|| {
13795                snapshot
13796                    .buffer_snapshot
13797                    .diff_hunks_in_range(Point::zero()..position)
13798                    .find(|hunk| hunk.row_range.end.0 < position.row)
13799            })
13800    }
13801
13802    fn go_to_prev_hunk(
13803        &mut self,
13804        _: &GoToPreviousHunk,
13805        window: &mut Window,
13806        cx: &mut Context<Self>,
13807    ) {
13808        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13809        let snapshot = self.snapshot(window, cx);
13810        let selection = self.selections.newest::<Point>(cx);
13811        self.go_to_hunk_before_or_after_position(
13812            &snapshot,
13813            selection.head(),
13814            Direction::Prev,
13815            window,
13816            cx,
13817        );
13818    }
13819
13820    fn hunk_before_position(
13821        &mut self,
13822        snapshot: &EditorSnapshot,
13823        position: Point,
13824    ) -> Option<MultiBufferRow> {
13825        snapshot
13826            .buffer_snapshot
13827            .diff_hunk_before(position)
13828            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13829    }
13830
13831    fn go_to_next_change(
13832        &mut self,
13833        _: &GoToNextChange,
13834        window: &mut Window,
13835        cx: &mut Context<Self>,
13836    ) {
13837        if let Some(selections) = self
13838            .change_list
13839            .next_change(1, Direction::Next)
13840            .map(|s| s.to_vec())
13841        {
13842            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13843                let map = s.display_map();
13844                s.select_display_ranges(selections.iter().map(|a| {
13845                    let point = a.to_display_point(&map);
13846                    point..point
13847                }))
13848            })
13849        }
13850    }
13851
13852    fn go_to_previous_change(
13853        &mut self,
13854        _: &GoToPreviousChange,
13855        window: &mut Window,
13856        cx: &mut Context<Self>,
13857    ) {
13858        if let Some(selections) = self
13859            .change_list
13860            .next_change(1, Direction::Prev)
13861            .map(|s| s.to_vec())
13862        {
13863            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13864                let map = s.display_map();
13865                s.select_display_ranges(selections.iter().map(|a| {
13866                    let point = a.to_display_point(&map);
13867                    point..point
13868                }))
13869            })
13870        }
13871    }
13872
13873    fn go_to_line<T: 'static>(
13874        &mut self,
13875        position: Anchor,
13876        highlight_color: Option<Hsla>,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        let snapshot = self.snapshot(window, cx).display_snapshot;
13881        let position = position.to_point(&snapshot.buffer_snapshot);
13882        let start = snapshot
13883            .buffer_snapshot
13884            .clip_point(Point::new(position.row, 0), Bias::Left);
13885        let end = start + Point::new(1, 0);
13886        let start = snapshot.buffer_snapshot.anchor_before(start);
13887        let end = snapshot.buffer_snapshot.anchor_before(end);
13888
13889        self.highlight_rows::<T>(
13890            start..end,
13891            highlight_color
13892                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
13893            Default::default(),
13894            cx,
13895        );
13896
13897        if self.buffer.read(cx).is_singleton() {
13898            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
13899        }
13900    }
13901
13902    pub fn go_to_definition(
13903        &mut self,
13904        _: &GoToDefinition,
13905        window: &mut Window,
13906        cx: &mut Context<Self>,
13907    ) -> Task<Result<Navigated>> {
13908        let definition =
13909            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
13910        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
13911        cx.spawn_in(window, async move |editor, cx| {
13912            if definition.await? == Navigated::Yes {
13913                return Ok(Navigated::Yes);
13914            }
13915            match fallback_strategy {
13916                GoToDefinitionFallback::None => Ok(Navigated::No),
13917                GoToDefinitionFallback::FindAllReferences => {
13918                    match editor.update_in(cx, |editor, window, cx| {
13919                        editor.find_all_references(&FindAllReferences, window, cx)
13920                    })? {
13921                        Some(references) => references.await,
13922                        None => Ok(Navigated::No),
13923                    }
13924                }
13925            }
13926        })
13927    }
13928
13929    pub fn go_to_declaration(
13930        &mut self,
13931        _: &GoToDeclaration,
13932        window: &mut Window,
13933        cx: &mut Context<Self>,
13934    ) -> Task<Result<Navigated>> {
13935        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
13936    }
13937
13938    pub fn go_to_declaration_split(
13939        &mut self,
13940        _: &GoToDeclaration,
13941        window: &mut Window,
13942        cx: &mut Context<Self>,
13943    ) -> Task<Result<Navigated>> {
13944        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
13945    }
13946
13947    pub fn go_to_implementation(
13948        &mut self,
13949        _: &GoToImplementation,
13950        window: &mut Window,
13951        cx: &mut Context<Self>,
13952    ) -> Task<Result<Navigated>> {
13953        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
13954    }
13955
13956    pub fn go_to_implementation_split(
13957        &mut self,
13958        _: &GoToImplementationSplit,
13959        window: &mut Window,
13960        cx: &mut Context<Self>,
13961    ) -> Task<Result<Navigated>> {
13962        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
13963    }
13964
13965    pub fn go_to_type_definition(
13966        &mut self,
13967        _: &GoToTypeDefinition,
13968        window: &mut Window,
13969        cx: &mut Context<Self>,
13970    ) -> Task<Result<Navigated>> {
13971        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
13972    }
13973
13974    pub fn go_to_definition_split(
13975        &mut self,
13976        _: &GoToDefinitionSplit,
13977        window: &mut Window,
13978        cx: &mut Context<Self>,
13979    ) -> Task<Result<Navigated>> {
13980        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
13981    }
13982
13983    pub fn go_to_type_definition_split(
13984        &mut self,
13985        _: &GoToTypeDefinitionSplit,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) -> Task<Result<Navigated>> {
13989        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
13990    }
13991
13992    fn go_to_definition_of_kind(
13993        &mut self,
13994        kind: GotoDefinitionKind,
13995        split: bool,
13996        window: &mut Window,
13997        cx: &mut Context<Self>,
13998    ) -> Task<Result<Navigated>> {
13999        let Some(provider) = self.semantics_provider.clone() else {
14000            return Task::ready(Ok(Navigated::No));
14001        };
14002        let head = self.selections.newest::<usize>(cx).head();
14003        let buffer = self.buffer.read(cx);
14004        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14005            text_anchor
14006        } else {
14007            return Task::ready(Ok(Navigated::No));
14008        };
14009
14010        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14011            return Task::ready(Ok(Navigated::No));
14012        };
14013
14014        cx.spawn_in(window, async move |editor, cx| {
14015            let definitions = definitions.await?;
14016            let navigated = editor
14017                .update_in(cx, |editor, window, cx| {
14018                    editor.navigate_to_hover_links(
14019                        Some(kind),
14020                        definitions
14021                            .into_iter()
14022                            .filter(|location| {
14023                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14024                            })
14025                            .map(HoverLink::Text)
14026                            .collect::<Vec<_>>(),
14027                        split,
14028                        window,
14029                        cx,
14030                    )
14031                })?
14032                .await?;
14033            anyhow::Ok(navigated)
14034        })
14035    }
14036
14037    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14038        let selection = self.selections.newest_anchor();
14039        let head = selection.head();
14040        let tail = selection.tail();
14041
14042        let Some((buffer, start_position)) =
14043            self.buffer.read(cx).text_anchor_for_position(head, cx)
14044        else {
14045            return;
14046        };
14047
14048        let end_position = if head != tail {
14049            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14050                return;
14051            };
14052            Some(pos)
14053        } else {
14054            None
14055        };
14056
14057        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14058            let url = if let Some(end_pos) = end_position {
14059                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14060            } else {
14061                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14062            };
14063
14064            if let Some(url) = url {
14065                editor.update(cx, |_, cx| {
14066                    cx.open_url(&url);
14067                })
14068            } else {
14069                Ok(())
14070            }
14071        });
14072
14073        url_finder.detach();
14074    }
14075
14076    pub fn open_selected_filename(
14077        &mut self,
14078        _: &OpenSelectedFilename,
14079        window: &mut Window,
14080        cx: &mut Context<Self>,
14081    ) {
14082        let Some(workspace) = self.workspace() else {
14083            return;
14084        };
14085
14086        let position = self.selections.newest_anchor().head();
14087
14088        let Some((buffer, buffer_position)) =
14089            self.buffer.read(cx).text_anchor_for_position(position, cx)
14090        else {
14091            return;
14092        };
14093
14094        let project = self.project.clone();
14095
14096        cx.spawn_in(window, async move |_, cx| {
14097            let result = find_file(&buffer, project, buffer_position, cx).await;
14098
14099            if let Some((_, path)) = result {
14100                workspace
14101                    .update_in(cx, |workspace, window, cx| {
14102                        workspace.open_resolved_path(path, window, cx)
14103                    })?
14104                    .await?;
14105            }
14106            anyhow::Ok(())
14107        })
14108        .detach();
14109    }
14110
14111    pub(crate) fn navigate_to_hover_links(
14112        &mut self,
14113        kind: Option<GotoDefinitionKind>,
14114        mut definitions: Vec<HoverLink>,
14115        split: bool,
14116        window: &mut Window,
14117        cx: &mut Context<Editor>,
14118    ) -> Task<Result<Navigated>> {
14119        // If there is one definition, just open it directly
14120        if definitions.len() == 1 {
14121            let definition = definitions.pop().unwrap();
14122
14123            enum TargetTaskResult {
14124                Location(Option<Location>),
14125                AlreadyNavigated,
14126            }
14127
14128            let target_task = match definition {
14129                HoverLink::Text(link) => {
14130                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14131                }
14132                HoverLink::InlayHint(lsp_location, server_id) => {
14133                    let computation =
14134                        self.compute_target_location(lsp_location, server_id, window, cx);
14135                    cx.background_spawn(async move {
14136                        let location = computation.await?;
14137                        Ok(TargetTaskResult::Location(location))
14138                    })
14139                }
14140                HoverLink::Url(url) => {
14141                    cx.open_url(&url);
14142                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14143                }
14144                HoverLink::File(path) => {
14145                    if let Some(workspace) = self.workspace() {
14146                        cx.spawn_in(window, async move |_, cx| {
14147                            workspace
14148                                .update_in(cx, |workspace, window, cx| {
14149                                    workspace.open_resolved_path(path, window, cx)
14150                                })?
14151                                .await
14152                                .map(|_| TargetTaskResult::AlreadyNavigated)
14153                        })
14154                    } else {
14155                        Task::ready(Ok(TargetTaskResult::Location(None)))
14156                    }
14157                }
14158            };
14159            cx.spawn_in(window, async move |editor, cx| {
14160                let target = match target_task.await.context("target resolution task")? {
14161                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14162                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14163                    TargetTaskResult::Location(Some(target)) => target,
14164                };
14165
14166                editor.update_in(cx, |editor, window, cx| {
14167                    let Some(workspace) = editor.workspace() else {
14168                        return Navigated::No;
14169                    };
14170                    let pane = workspace.read(cx).active_pane().clone();
14171
14172                    let range = target.range.to_point(target.buffer.read(cx));
14173                    let range = editor.range_for_match(&range);
14174                    let range = collapse_multiline_range(range);
14175
14176                    if !split
14177                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14178                    {
14179                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14180                    } else {
14181                        window.defer(cx, move |window, cx| {
14182                            let target_editor: Entity<Self> =
14183                                workspace.update(cx, |workspace, cx| {
14184                                    let pane = if split {
14185                                        workspace.adjacent_pane(window, cx)
14186                                    } else {
14187                                        workspace.active_pane().clone()
14188                                    };
14189
14190                                    workspace.open_project_item(
14191                                        pane,
14192                                        target.buffer.clone(),
14193                                        true,
14194                                        true,
14195                                        window,
14196                                        cx,
14197                                    )
14198                                });
14199                            target_editor.update(cx, |target_editor, cx| {
14200                                // When selecting a definition in a different buffer, disable the nav history
14201                                // to avoid creating a history entry at the previous cursor location.
14202                                pane.update(cx, |pane, _| pane.disable_history());
14203                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14204                                pane.update(cx, |pane, _| pane.enable_history());
14205                            });
14206                        });
14207                    }
14208                    Navigated::Yes
14209                })
14210            })
14211        } else if !definitions.is_empty() {
14212            cx.spawn_in(window, async move |editor, cx| {
14213                let (title, location_tasks, workspace) = editor
14214                    .update_in(cx, |editor, window, cx| {
14215                        let tab_kind = match kind {
14216                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14217                            _ => "Definitions",
14218                        };
14219                        let title = definitions
14220                            .iter()
14221                            .find_map(|definition| match definition {
14222                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14223                                    let buffer = origin.buffer.read(cx);
14224                                    format!(
14225                                        "{} for {}",
14226                                        tab_kind,
14227                                        buffer
14228                                            .text_for_range(origin.range.clone())
14229                                            .collect::<String>()
14230                                    )
14231                                }),
14232                                HoverLink::InlayHint(_, _) => None,
14233                                HoverLink::Url(_) => None,
14234                                HoverLink::File(_) => None,
14235                            })
14236                            .unwrap_or(tab_kind.to_string());
14237                        let location_tasks = definitions
14238                            .into_iter()
14239                            .map(|definition| match definition {
14240                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14241                                HoverLink::InlayHint(lsp_location, server_id) => editor
14242                                    .compute_target_location(lsp_location, server_id, window, cx),
14243                                HoverLink::Url(_) => Task::ready(Ok(None)),
14244                                HoverLink::File(_) => Task::ready(Ok(None)),
14245                            })
14246                            .collect::<Vec<_>>();
14247                        (title, location_tasks, editor.workspace().clone())
14248                    })
14249                    .context("location tasks preparation")?;
14250
14251                let locations = future::join_all(location_tasks)
14252                    .await
14253                    .into_iter()
14254                    .filter_map(|location| location.transpose())
14255                    .collect::<Result<_>>()
14256                    .context("location tasks")?;
14257
14258                let Some(workspace) = workspace else {
14259                    return Ok(Navigated::No);
14260                };
14261                let opened = workspace
14262                    .update_in(cx, |workspace, window, cx| {
14263                        Self::open_locations_in_multibuffer(
14264                            workspace,
14265                            locations,
14266                            title,
14267                            split,
14268                            MultibufferSelectionMode::First,
14269                            window,
14270                            cx,
14271                        )
14272                    })
14273                    .ok();
14274
14275                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14276            })
14277        } else {
14278            Task::ready(Ok(Navigated::No))
14279        }
14280    }
14281
14282    fn compute_target_location(
14283        &self,
14284        lsp_location: lsp::Location,
14285        server_id: LanguageServerId,
14286        window: &mut Window,
14287        cx: &mut Context<Self>,
14288    ) -> Task<anyhow::Result<Option<Location>>> {
14289        let Some(project) = self.project.clone() else {
14290            return Task::ready(Ok(None));
14291        };
14292
14293        cx.spawn_in(window, async move |editor, cx| {
14294            let location_task = editor.update(cx, |_, cx| {
14295                project.update(cx, |project, cx| {
14296                    let language_server_name = project
14297                        .language_server_statuses(cx)
14298                        .find(|(id, _)| server_id == *id)
14299                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14300                    language_server_name.map(|language_server_name| {
14301                        project.open_local_buffer_via_lsp(
14302                            lsp_location.uri.clone(),
14303                            server_id,
14304                            language_server_name,
14305                            cx,
14306                        )
14307                    })
14308                })
14309            })?;
14310            let location = match location_task {
14311                Some(task) => Some({
14312                    let target_buffer_handle = task.await.context("open local buffer")?;
14313                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14314                        let target_start = target_buffer
14315                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14316                        let target_end = target_buffer
14317                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14318                        target_buffer.anchor_after(target_start)
14319                            ..target_buffer.anchor_before(target_end)
14320                    })?;
14321                    Location {
14322                        buffer: target_buffer_handle,
14323                        range,
14324                    }
14325                }),
14326                None => None,
14327            };
14328            Ok(location)
14329        })
14330    }
14331
14332    pub fn find_all_references(
14333        &mut self,
14334        _: &FindAllReferences,
14335        window: &mut Window,
14336        cx: &mut Context<Self>,
14337    ) -> Option<Task<Result<Navigated>>> {
14338        let selection = self.selections.newest::<usize>(cx);
14339        let multi_buffer = self.buffer.read(cx);
14340        let head = selection.head();
14341
14342        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14343        let head_anchor = multi_buffer_snapshot.anchor_at(
14344            head,
14345            if head < selection.tail() {
14346                Bias::Right
14347            } else {
14348                Bias::Left
14349            },
14350        );
14351
14352        match self
14353            .find_all_references_task_sources
14354            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14355        {
14356            Ok(_) => {
14357                log::info!(
14358                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14359                );
14360                return None;
14361            }
14362            Err(i) => {
14363                self.find_all_references_task_sources.insert(i, head_anchor);
14364            }
14365        }
14366
14367        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14368        let workspace = self.workspace()?;
14369        let project = workspace.read(cx).project().clone();
14370        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14371        Some(cx.spawn_in(window, async move |editor, cx| {
14372            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14373                if let Ok(i) = editor
14374                    .find_all_references_task_sources
14375                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14376                {
14377                    editor.find_all_references_task_sources.remove(i);
14378                }
14379            });
14380
14381            let locations = references.await?;
14382            if locations.is_empty() {
14383                return anyhow::Ok(Navigated::No);
14384            }
14385
14386            workspace.update_in(cx, |workspace, window, cx| {
14387                let title = locations
14388                    .first()
14389                    .as_ref()
14390                    .map(|location| {
14391                        let buffer = location.buffer.read(cx);
14392                        format!(
14393                            "References to `{}`",
14394                            buffer
14395                                .text_for_range(location.range.clone())
14396                                .collect::<String>()
14397                        )
14398                    })
14399                    .unwrap();
14400                Self::open_locations_in_multibuffer(
14401                    workspace,
14402                    locations,
14403                    title,
14404                    false,
14405                    MultibufferSelectionMode::First,
14406                    window,
14407                    cx,
14408                );
14409                Navigated::Yes
14410            })
14411        }))
14412    }
14413
14414    /// Opens a multibuffer with the given project locations in it
14415    pub fn open_locations_in_multibuffer(
14416        workspace: &mut Workspace,
14417        mut locations: Vec<Location>,
14418        title: String,
14419        split: bool,
14420        multibuffer_selection_mode: MultibufferSelectionMode,
14421        window: &mut Window,
14422        cx: &mut Context<Workspace>,
14423    ) {
14424        // If there are multiple definitions, open them in a multibuffer
14425        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14426        let mut locations = locations.into_iter().peekable();
14427        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14428        let capability = workspace.project().read(cx).capability();
14429
14430        let excerpt_buffer = cx.new(|cx| {
14431            let mut multibuffer = MultiBuffer::new(capability);
14432            while let Some(location) = locations.next() {
14433                let buffer = location.buffer.read(cx);
14434                let mut ranges_for_buffer = Vec::new();
14435                let range = location.range.to_point(buffer);
14436                ranges_for_buffer.push(range.clone());
14437
14438                while let Some(next_location) = locations.peek() {
14439                    if next_location.buffer == location.buffer {
14440                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14441                        locations.next();
14442                    } else {
14443                        break;
14444                    }
14445                }
14446
14447                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14448                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14449                    PathKey::for_buffer(&location.buffer, cx),
14450                    location.buffer.clone(),
14451                    ranges_for_buffer,
14452                    DEFAULT_MULTIBUFFER_CONTEXT,
14453                    cx,
14454                );
14455                ranges.extend(new_ranges)
14456            }
14457
14458            multibuffer.with_title(title)
14459        });
14460
14461        let editor = cx.new(|cx| {
14462            Editor::for_multibuffer(
14463                excerpt_buffer,
14464                Some(workspace.project().clone()),
14465                window,
14466                cx,
14467            )
14468        });
14469        editor.update(cx, |editor, cx| {
14470            match multibuffer_selection_mode {
14471                MultibufferSelectionMode::First => {
14472                    if let Some(first_range) = ranges.first() {
14473                        editor.change_selections(None, window, cx, |selections| {
14474                            selections.clear_disjoint();
14475                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14476                        });
14477                    }
14478                    editor.highlight_background::<Self>(
14479                        &ranges,
14480                        |theme| theme.editor_highlighted_line_background,
14481                        cx,
14482                    );
14483                }
14484                MultibufferSelectionMode::All => {
14485                    editor.change_selections(None, window, cx, |selections| {
14486                        selections.clear_disjoint();
14487                        selections.select_anchor_ranges(ranges);
14488                    });
14489                }
14490            }
14491            editor.register_buffers_with_language_servers(cx);
14492        });
14493
14494        let item = Box::new(editor);
14495        let item_id = item.item_id();
14496
14497        if split {
14498            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14499        } else {
14500            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14501                let (preview_item_id, preview_item_idx) =
14502                    workspace.active_pane().update(cx, |pane, _| {
14503                        (pane.preview_item_id(), pane.preview_item_idx())
14504                    });
14505
14506                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14507
14508                if let Some(preview_item_id) = preview_item_id {
14509                    workspace.active_pane().update(cx, |pane, cx| {
14510                        pane.remove_item(preview_item_id, false, false, window, cx);
14511                    });
14512                }
14513            } else {
14514                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14515            }
14516        }
14517        workspace.active_pane().update(cx, |pane, cx| {
14518            pane.set_preview_item_id(Some(item_id), cx);
14519        });
14520    }
14521
14522    pub fn rename(
14523        &mut self,
14524        _: &Rename,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) -> Option<Task<Result<()>>> {
14528        use language::ToOffset as _;
14529
14530        let provider = self.semantics_provider.clone()?;
14531        let selection = self.selections.newest_anchor().clone();
14532        let (cursor_buffer, cursor_buffer_position) = self
14533            .buffer
14534            .read(cx)
14535            .text_anchor_for_position(selection.head(), cx)?;
14536        let (tail_buffer, cursor_buffer_position_end) = self
14537            .buffer
14538            .read(cx)
14539            .text_anchor_for_position(selection.tail(), cx)?;
14540        if tail_buffer != cursor_buffer {
14541            return None;
14542        }
14543
14544        let snapshot = cursor_buffer.read(cx).snapshot();
14545        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14546        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14547        let prepare_rename = provider
14548            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14549            .unwrap_or_else(|| Task::ready(Ok(None)));
14550        drop(snapshot);
14551
14552        Some(cx.spawn_in(window, async move |this, cx| {
14553            let rename_range = if let Some(range) = prepare_rename.await? {
14554                Some(range)
14555            } else {
14556                this.update(cx, |this, cx| {
14557                    let buffer = this.buffer.read(cx).snapshot(cx);
14558                    let mut buffer_highlights = this
14559                        .document_highlights_for_position(selection.head(), &buffer)
14560                        .filter(|highlight| {
14561                            highlight.start.excerpt_id == selection.head().excerpt_id
14562                                && highlight.end.excerpt_id == selection.head().excerpt_id
14563                        });
14564                    buffer_highlights
14565                        .next()
14566                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14567                })?
14568            };
14569            if let Some(rename_range) = rename_range {
14570                this.update_in(cx, |this, window, cx| {
14571                    let snapshot = cursor_buffer.read(cx).snapshot();
14572                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14573                    let cursor_offset_in_rename_range =
14574                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14575                    let cursor_offset_in_rename_range_end =
14576                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14577
14578                    this.take_rename(false, window, cx);
14579                    let buffer = this.buffer.read(cx).read(cx);
14580                    let cursor_offset = selection.head().to_offset(&buffer);
14581                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14582                    let rename_end = rename_start + rename_buffer_range.len();
14583                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14584                    let mut old_highlight_id = None;
14585                    let old_name: Arc<str> = buffer
14586                        .chunks(rename_start..rename_end, true)
14587                        .map(|chunk| {
14588                            if old_highlight_id.is_none() {
14589                                old_highlight_id = chunk.syntax_highlight_id;
14590                            }
14591                            chunk.text
14592                        })
14593                        .collect::<String>()
14594                        .into();
14595
14596                    drop(buffer);
14597
14598                    // Position the selection in the rename editor so that it matches the current selection.
14599                    this.show_local_selections = false;
14600                    let rename_editor = cx.new(|cx| {
14601                        let mut editor = Editor::single_line(window, cx);
14602                        editor.buffer.update(cx, |buffer, cx| {
14603                            buffer.edit([(0..0, old_name.clone())], None, cx)
14604                        });
14605                        let rename_selection_range = match cursor_offset_in_rename_range
14606                            .cmp(&cursor_offset_in_rename_range_end)
14607                        {
14608                            Ordering::Equal => {
14609                                editor.select_all(&SelectAll, window, cx);
14610                                return editor;
14611                            }
14612                            Ordering::Less => {
14613                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14614                            }
14615                            Ordering::Greater => {
14616                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14617                            }
14618                        };
14619                        if rename_selection_range.end > old_name.len() {
14620                            editor.select_all(&SelectAll, window, cx);
14621                        } else {
14622                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14623                                s.select_ranges([rename_selection_range]);
14624                            });
14625                        }
14626                        editor
14627                    });
14628                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14629                        if e == &EditorEvent::Focused {
14630                            cx.emit(EditorEvent::FocusedIn)
14631                        }
14632                    })
14633                    .detach();
14634
14635                    let write_highlights =
14636                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14637                    let read_highlights =
14638                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14639                    let ranges = write_highlights
14640                        .iter()
14641                        .flat_map(|(_, ranges)| ranges.iter())
14642                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14643                        .cloned()
14644                        .collect();
14645
14646                    this.highlight_text::<Rename>(
14647                        ranges,
14648                        HighlightStyle {
14649                            fade_out: Some(0.6),
14650                            ..Default::default()
14651                        },
14652                        cx,
14653                    );
14654                    let rename_focus_handle = rename_editor.focus_handle(cx);
14655                    window.focus(&rename_focus_handle);
14656                    let block_id = this.insert_blocks(
14657                        [BlockProperties {
14658                            style: BlockStyle::Flex,
14659                            placement: BlockPlacement::Below(range.start),
14660                            height: Some(1),
14661                            render: Arc::new({
14662                                let rename_editor = rename_editor.clone();
14663                                move |cx: &mut BlockContext| {
14664                                    let mut text_style = cx.editor_style.text.clone();
14665                                    if let Some(highlight_style) = old_highlight_id
14666                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14667                                    {
14668                                        text_style = text_style.highlight(highlight_style);
14669                                    }
14670                                    div()
14671                                        .block_mouse_down()
14672                                        .pl(cx.anchor_x)
14673                                        .child(EditorElement::new(
14674                                            &rename_editor,
14675                                            EditorStyle {
14676                                                background: cx.theme().system().transparent,
14677                                                local_player: cx.editor_style.local_player,
14678                                                text: text_style,
14679                                                scrollbar_width: cx.editor_style.scrollbar_width,
14680                                                syntax: cx.editor_style.syntax.clone(),
14681                                                status: cx.editor_style.status.clone(),
14682                                                inlay_hints_style: HighlightStyle {
14683                                                    font_weight: Some(FontWeight::BOLD),
14684                                                    ..make_inlay_hints_style(cx.app)
14685                                                },
14686                                                inline_completion_styles: make_suggestion_styles(
14687                                                    cx.app,
14688                                                ),
14689                                                ..EditorStyle::default()
14690                                            },
14691                                        ))
14692                                        .into_any_element()
14693                                }
14694                            }),
14695                            priority: 0,
14696                            render_in_minimap: true,
14697                        }],
14698                        Some(Autoscroll::fit()),
14699                        cx,
14700                    )[0];
14701                    this.pending_rename = Some(RenameState {
14702                        range,
14703                        old_name,
14704                        editor: rename_editor,
14705                        block_id,
14706                    });
14707                })?;
14708            }
14709
14710            Ok(())
14711        }))
14712    }
14713
14714    pub fn confirm_rename(
14715        &mut self,
14716        _: &ConfirmRename,
14717        window: &mut Window,
14718        cx: &mut Context<Self>,
14719    ) -> Option<Task<Result<()>>> {
14720        let rename = self.take_rename(false, window, cx)?;
14721        let workspace = self.workspace()?.downgrade();
14722        let (buffer, start) = self
14723            .buffer
14724            .read(cx)
14725            .text_anchor_for_position(rename.range.start, cx)?;
14726        let (end_buffer, _) = self
14727            .buffer
14728            .read(cx)
14729            .text_anchor_for_position(rename.range.end, cx)?;
14730        if buffer != end_buffer {
14731            return None;
14732        }
14733
14734        let old_name = rename.old_name;
14735        let new_name = rename.editor.read(cx).text(cx);
14736
14737        let rename = self.semantics_provider.as_ref()?.perform_rename(
14738            &buffer,
14739            start,
14740            new_name.clone(),
14741            cx,
14742        )?;
14743
14744        Some(cx.spawn_in(window, async move |editor, cx| {
14745            let project_transaction = rename.await?;
14746            Self::open_project_transaction(
14747                &editor,
14748                workspace,
14749                project_transaction,
14750                format!("Rename: {}{}", old_name, new_name),
14751                cx,
14752            )
14753            .await?;
14754
14755            editor.update(cx, |editor, cx| {
14756                editor.refresh_document_highlights(cx);
14757            })?;
14758            Ok(())
14759        }))
14760    }
14761
14762    fn take_rename(
14763        &mut self,
14764        moving_cursor: bool,
14765        window: &mut Window,
14766        cx: &mut Context<Self>,
14767    ) -> Option<RenameState> {
14768        let rename = self.pending_rename.take()?;
14769        if rename.editor.focus_handle(cx).is_focused(window) {
14770            window.focus(&self.focus_handle);
14771        }
14772
14773        self.remove_blocks(
14774            [rename.block_id].into_iter().collect(),
14775            Some(Autoscroll::fit()),
14776            cx,
14777        );
14778        self.clear_highlights::<Rename>(cx);
14779        self.show_local_selections = true;
14780
14781        if moving_cursor {
14782            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14783                editor.selections.newest::<usize>(cx).head()
14784            });
14785
14786            // Update the selection to match the position of the selection inside
14787            // the rename editor.
14788            let snapshot = self.buffer.read(cx).read(cx);
14789            let rename_range = rename.range.to_offset(&snapshot);
14790            let cursor_in_editor = snapshot
14791                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14792                .min(rename_range.end);
14793            drop(snapshot);
14794
14795            self.change_selections(None, window, cx, |s| {
14796                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14797            });
14798        } else {
14799            self.refresh_document_highlights(cx);
14800        }
14801
14802        Some(rename)
14803    }
14804
14805    pub fn pending_rename(&self) -> Option<&RenameState> {
14806        self.pending_rename.as_ref()
14807    }
14808
14809    fn format(
14810        &mut self,
14811        _: &Format,
14812        window: &mut Window,
14813        cx: &mut Context<Self>,
14814    ) -> Option<Task<Result<()>>> {
14815        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14816
14817        let project = match &self.project {
14818            Some(project) => project.clone(),
14819            None => return None,
14820        };
14821
14822        Some(self.perform_format(
14823            project,
14824            FormatTrigger::Manual,
14825            FormatTarget::Buffers,
14826            window,
14827            cx,
14828        ))
14829    }
14830
14831    fn format_selections(
14832        &mut self,
14833        _: &FormatSelections,
14834        window: &mut Window,
14835        cx: &mut Context<Self>,
14836    ) -> Option<Task<Result<()>>> {
14837        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14838
14839        let project = match &self.project {
14840            Some(project) => project.clone(),
14841            None => return None,
14842        };
14843
14844        let ranges = self
14845            .selections
14846            .all_adjusted(cx)
14847            .into_iter()
14848            .map(|selection| selection.range())
14849            .collect_vec();
14850
14851        Some(self.perform_format(
14852            project,
14853            FormatTrigger::Manual,
14854            FormatTarget::Ranges(ranges),
14855            window,
14856            cx,
14857        ))
14858    }
14859
14860    fn perform_format(
14861        &mut self,
14862        project: Entity<Project>,
14863        trigger: FormatTrigger,
14864        target: FormatTarget,
14865        window: &mut Window,
14866        cx: &mut Context<Self>,
14867    ) -> Task<Result<()>> {
14868        let buffer = self.buffer.clone();
14869        let (buffers, target) = match target {
14870            FormatTarget::Buffers => {
14871                let mut buffers = buffer.read(cx).all_buffers();
14872                if trigger == FormatTrigger::Save {
14873                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
14874                }
14875                (buffers, LspFormatTarget::Buffers)
14876            }
14877            FormatTarget::Ranges(selection_ranges) => {
14878                let multi_buffer = buffer.read(cx);
14879                let snapshot = multi_buffer.read(cx);
14880                let mut buffers = HashSet::default();
14881                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
14882                    BTreeMap::new();
14883                for selection_range in selection_ranges {
14884                    for (buffer, buffer_range, _) in
14885                        snapshot.range_to_buffer_ranges(selection_range)
14886                    {
14887                        let buffer_id = buffer.remote_id();
14888                        let start = buffer.anchor_before(buffer_range.start);
14889                        let end = buffer.anchor_after(buffer_range.end);
14890                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
14891                        buffer_id_to_ranges
14892                            .entry(buffer_id)
14893                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
14894                            .or_insert_with(|| vec![start..end]);
14895                    }
14896                }
14897                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
14898            }
14899        };
14900
14901        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
14902        let selections_prev = transaction_id_prev
14903            .and_then(|transaction_id_prev| {
14904                // default to selections as they were after the last edit, if we have them,
14905                // instead of how they are now.
14906                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
14907                // will take you back to where you made the last edit, instead of staying where you scrolled
14908                self.selection_history
14909                    .transaction(transaction_id_prev)
14910                    .map(|t| t.0.clone())
14911            })
14912            .unwrap_or_else(|| {
14913                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
14914                self.selections.disjoint_anchors()
14915            });
14916
14917        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
14918        let format = project.update(cx, |project, cx| {
14919            project.format(buffers, target, true, trigger, cx)
14920        });
14921
14922        cx.spawn_in(window, async move |editor, cx| {
14923            let transaction = futures::select_biased! {
14924                transaction = format.log_err().fuse() => transaction,
14925                () = timeout => {
14926                    log::warn!("timed out waiting for formatting");
14927                    None
14928                }
14929            };
14930
14931            buffer
14932                .update(cx, |buffer, cx| {
14933                    if let Some(transaction) = transaction {
14934                        if !buffer.is_singleton() {
14935                            buffer.push_transaction(&transaction.0, cx);
14936                        }
14937                    }
14938                    cx.notify();
14939                })
14940                .ok();
14941
14942            if let Some(transaction_id_now) =
14943                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
14944            {
14945                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
14946                if has_new_transaction {
14947                    _ = editor.update(cx, |editor, _| {
14948                        editor
14949                            .selection_history
14950                            .insert_transaction(transaction_id_now, selections_prev);
14951                    });
14952                }
14953            }
14954
14955            Ok(())
14956        })
14957    }
14958
14959    fn organize_imports(
14960        &mut self,
14961        _: &OrganizeImports,
14962        window: &mut Window,
14963        cx: &mut Context<Self>,
14964    ) -> Option<Task<Result<()>>> {
14965        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14966        let project = match &self.project {
14967            Some(project) => project.clone(),
14968            None => return None,
14969        };
14970        Some(self.perform_code_action_kind(
14971            project,
14972            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
14973            window,
14974            cx,
14975        ))
14976    }
14977
14978    fn perform_code_action_kind(
14979        &mut self,
14980        project: Entity<Project>,
14981        kind: CodeActionKind,
14982        window: &mut Window,
14983        cx: &mut Context<Self>,
14984    ) -> Task<Result<()>> {
14985        let buffer = self.buffer.clone();
14986        let buffers = buffer.read(cx).all_buffers();
14987        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
14988        let apply_action = project.update(cx, |project, cx| {
14989            project.apply_code_action_kind(buffers, kind, true, cx)
14990        });
14991        cx.spawn_in(window, async move |_, cx| {
14992            let transaction = futures::select_biased! {
14993                () = timeout => {
14994                    log::warn!("timed out waiting for executing code action");
14995                    None
14996                }
14997                transaction = apply_action.log_err().fuse() => transaction,
14998            };
14999            buffer
15000                .update(cx, |buffer, cx| {
15001                    // check if we need this
15002                    if let Some(transaction) = transaction {
15003                        if !buffer.is_singleton() {
15004                            buffer.push_transaction(&transaction.0, cx);
15005                        }
15006                    }
15007                    cx.notify();
15008                })
15009                .ok();
15010            Ok(())
15011        })
15012    }
15013
15014    fn restart_language_server(
15015        &mut self,
15016        _: &RestartLanguageServer,
15017        _: &mut Window,
15018        cx: &mut Context<Self>,
15019    ) {
15020        if let Some(project) = self.project.clone() {
15021            self.buffer.update(cx, |multi_buffer, cx| {
15022                project.update(cx, |project, cx| {
15023                    project.restart_language_servers_for_buffers(
15024                        multi_buffer.all_buffers().into_iter().collect(),
15025                        cx,
15026                    );
15027                });
15028            })
15029        }
15030    }
15031
15032    fn stop_language_server(
15033        &mut self,
15034        _: &StopLanguageServer,
15035        _: &mut Window,
15036        cx: &mut Context<Self>,
15037    ) {
15038        if let Some(project) = self.project.clone() {
15039            self.buffer.update(cx, |multi_buffer, cx| {
15040                project.update(cx, |project, cx| {
15041                    project.stop_language_servers_for_buffers(
15042                        multi_buffer.all_buffers().into_iter().collect(),
15043                        cx,
15044                    );
15045                    cx.emit(project::Event::RefreshInlayHints);
15046                });
15047            });
15048        }
15049    }
15050
15051    fn cancel_language_server_work(
15052        workspace: &mut Workspace,
15053        _: &actions::CancelLanguageServerWork,
15054        _: &mut Window,
15055        cx: &mut Context<Workspace>,
15056    ) {
15057        let project = workspace.project();
15058        let buffers = workspace
15059            .active_item(cx)
15060            .and_then(|item| item.act_as::<Editor>(cx))
15061            .map_or(HashSet::default(), |editor| {
15062                editor.read(cx).buffer.read(cx).all_buffers()
15063            });
15064        project.update(cx, |project, cx| {
15065            project.cancel_language_server_work_for_buffers(buffers, cx);
15066        });
15067    }
15068
15069    fn show_character_palette(
15070        &mut self,
15071        _: &ShowCharacterPalette,
15072        window: &mut Window,
15073        _: &mut Context<Self>,
15074    ) {
15075        window.show_character_palette();
15076    }
15077
15078    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15079        if self.mode.is_minimap() {
15080            return;
15081        }
15082
15083        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15084            let buffer = self.buffer.read(cx).snapshot(cx);
15085            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15086            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15087            let is_valid = buffer
15088                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15089                .any(|entry| {
15090                    entry.diagnostic.is_primary
15091                        && !entry.range.is_empty()
15092                        && entry.range.start == primary_range_start
15093                        && entry.diagnostic.message == active_diagnostics.active_message
15094                });
15095
15096            if !is_valid {
15097                self.dismiss_diagnostics(cx);
15098            }
15099        }
15100    }
15101
15102    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15103        match &self.active_diagnostics {
15104            ActiveDiagnostic::Group(group) => Some(group),
15105            _ => None,
15106        }
15107    }
15108
15109    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15110        self.dismiss_diagnostics(cx);
15111        self.active_diagnostics = ActiveDiagnostic::All;
15112    }
15113
15114    fn activate_diagnostics(
15115        &mut self,
15116        buffer_id: BufferId,
15117        diagnostic: DiagnosticEntry<usize>,
15118        window: &mut Window,
15119        cx: &mut Context<Self>,
15120    ) {
15121        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15122            return;
15123        }
15124        self.dismiss_diagnostics(cx);
15125        let snapshot = self.snapshot(window, cx);
15126        let buffer = self.buffer.read(cx).snapshot(cx);
15127        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15128            return;
15129        };
15130
15131        let diagnostic_group = buffer
15132            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15133            .collect::<Vec<_>>();
15134
15135        let blocks =
15136            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15137
15138        let blocks = self.display_map.update(cx, |display_map, cx| {
15139            display_map.insert_blocks(blocks, cx).into_iter().collect()
15140        });
15141        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15142            active_range: buffer.anchor_before(diagnostic.range.start)
15143                ..buffer.anchor_after(diagnostic.range.end),
15144            active_message: diagnostic.diagnostic.message.clone(),
15145            group_id: diagnostic.diagnostic.group_id,
15146            blocks,
15147        });
15148        cx.notify();
15149    }
15150
15151    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15152        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15153            return;
15154        };
15155
15156        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15157        if let ActiveDiagnostic::Group(group) = prev {
15158            self.display_map.update(cx, |display_map, cx| {
15159                display_map.remove_blocks(group.blocks, cx);
15160            });
15161            cx.notify();
15162        }
15163    }
15164
15165    /// Disable inline diagnostics rendering for this editor.
15166    pub fn disable_inline_diagnostics(&mut self) {
15167        self.inline_diagnostics_enabled = false;
15168        self.inline_diagnostics_update = Task::ready(());
15169        self.inline_diagnostics.clear();
15170    }
15171
15172    pub fn diagnostics_enabled(&self) -> bool {
15173        self.mode.is_full()
15174    }
15175
15176    pub fn inline_diagnostics_enabled(&self) -> bool {
15177        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15178    }
15179
15180    pub fn show_inline_diagnostics(&self) -> bool {
15181        self.show_inline_diagnostics
15182    }
15183
15184    pub fn toggle_inline_diagnostics(
15185        &mut self,
15186        _: &ToggleInlineDiagnostics,
15187        window: &mut Window,
15188        cx: &mut Context<Editor>,
15189    ) {
15190        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15191        self.refresh_inline_diagnostics(false, window, cx);
15192    }
15193
15194    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15195        self.diagnostics_max_severity = severity;
15196        self.display_map.update(cx, |display_map, _| {
15197            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15198        });
15199    }
15200
15201    pub fn toggle_diagnostics(
15202        &mut self,
15203        _: &ToggleDiagnostics,
15204        window: &mut Window,
15205        cx: &mut Context<Editor>,
15206    ) {
15207        if !self.diagnostics_enabled() {
15208            return;
15209        }
15210
15211        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15212            EditorSettings::get_global(cx)
15213                .diagnostics_max_severity
15214                .filter(|severity| severity != &DiagnosticSeverity::Off)
15215                .unwrap_or(DiagnosticSeverity::Hint)
15216        } else {
15217            DiagnosticSeverity::Off
15218        };
15219        self.set_max_diagnostics_severity(new_severity, cx);
15220        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15221            self.active_diagnostics = ActiveDiagnostic::None;
15222            self.inline_diagnostics_update = Task::ready(());
15223            self.inline_diagnostics.clear();
15224        } else {
15225            self.refresh_inline_diagnostics(false, window, cx);
15226        }
15227
15228        cx.notify();
15229    }
15230
15231    pub fn toggle_minimap(
15232        &mut self,
15233        _: &ToggleMinimap,
15234        window: &mut Window,
15235        cx: &mut Context<Editor>,
15236    ) {
15237        if self.supports_minimap(cx) {
15238            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15239        }
15240    }
15241
15242    fn refresh_inline_diagnostics(
15243        &mut self,
15244        debounce: bool,
15245        window: &mut Window,
15246        cx: &mut Context<Self>,
15247    ) {
15248        let max_severity = ProjectSettings::get_global(cx)
15249            .diagnostics
15250            .inline
15251            .max_severity
15252            .unwrap_or(self.diagnostics_max_severity);
15253
15254        if self.mode.is_minimap()
15255            || !self.inline_diagnostics_enabled()
15256            || !self.show_inline_diagnostics
15257            || max_severity == DiagnosticSeverity::Off
15258        {
15259            self.inline_diagnostics_update = Task::ready(());
15260            self.inline_diagnostics.clear();
15261            return;
15262        }
15263
15264        let debounce_ms = ProjectSettings::get_global(cx)
15265            .diagnostics
15266            .inline
15267            .update_debounce_ms;
15268        let debounce = if debounce && debounce_ms > 0 {
15269            Some(Duration::from_millis(debounce_ms))
15270        } else {
15271            None
15272        };
15273        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15274            let editor = editor.upgrade().unwrap();
15275
15276            if let Some(debounce) = debounce {
15277                cx.background_executor().timer(debounce).await;
15278            }
15279            let Some(snapshot) = editor
15280                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15281                .ok()
15282            else {
15283                return;
15284            };
15285
15286            let new_inline_diagnostics = cx
15287                .background_spawn(async move {
15288                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15289                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15290                        let message = diagnostic_entry
15291                            .diagnostic
15292                            .message
15293                            .split_once('\n')
15294                            .map(|(line, _)| line)
15295                            .map(SharedString::new)
15296                            .unwrap_or_else(|| {
15297                                SharedString::from(diagnostic_entry.diagnostic.message)
15298                            });
15299                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15300                        let (Ok(i) | Err(i)) = inline_diagnostics
15301                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15302                        inline_diagnostics.insert(
15303                            i,
15304                            (
15305                                start_anchor,
15306                                InlineDiagnostic {
15307                                    message,
15308                                    group_id: diagnostic_entry.diagnostic.group_id,
15309                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15310                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15311                                    severity: diagnostic_entry.diagnostic.severity,
15312                                },
15313                            ),
15314                        );
15315                    }
15316                    inline_diagnostics
15317                })
15318                .await;
15319
15320            editor
15321                .update(cx, |editor, cx| {
15322                    editor.inline_diagnostics = new_inline_diagnostics;
15323                    cx.notify();
15324                })
15325                .ok();
15326        });
15327    }
15328
15329    pub fn set_selections_from_remote(
15330        &mut self,
15331        selections: Vec<Selection<Anchor>>,
15332        pending_selection: Option<Selection<Anchor>>,
15333        window: &mut Window,
15334        cx: &mut Context<Self>,
15335    ) {
15336        let old_cursor_position = self.selections.newest_anchor().head();
15337        self.selections.change_with(cx, |s| {
15338            s.select_anchors(selections);
15339            if let Some(pending_selection) = pending_selection {
15340                s.set_pending(pending_selection, SelectMode::Character);
15341            } else {
15342                s.clear_pending();
15343            }
15344        });
15345        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15346    }
15347
15348    fn push_to_selection_history(&mut self) {
15349        self.selection_history.push(SelectionHistoryEntry {
15350            selections: self.selections.disjoint_anchors(),
15351            select_next_state: self.select_next_state.clone(),
15352            select_prev_state: self.select_prev_state.clone(),
15353            add_selections_state: self.add_selections_state.clone(),
15354        });
15355    }
15356
15357    pub fn transact(
15358        &mut self,
15359        window: &mut Window,
15360        cx: &mut Context<Self>,
15361        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15362    ) -> Option<TransactionId> {
15363        self.start_transaction_at(Instant::now(), window, cx);
15364        update(self, window, cx);
15365        self.end_transaction_at(Instant::now(), cx)
15366    }
15367
15368    pub fn start_transaction_at(
15369        &mut self,
15370        now: Instant,
15371        window: &mut Window,
15372        cx: &mut Context<Self>,
15373    ) {
15374        self.end_selection(window, cx);
15375        if let Some(tx_id) = self
15376            .buffer
15377            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15378        {
15379            self.selection_history
15380                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15381            cx.emit(EditorEvent::TransactionBegun {
15382                transaction_id: tx_id,
15383            })
15384        }
15385    }
15386
15387    pub fn end_transaction_at(
15388        &mut self,
15389        now: Instant,
15390        cx: &mut Context<Self>,
15391    ) -> Option<TransactionId> {
15392        if let Some(transaction_id) = self
15393            .buffer
15394            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15395        {
15396            if let Some((_, end_selections)) =
15397                self.selection_history.transaction_mut(transaction_id)
15398            {
15399                *end_selections = Some(self.selections.disjoint_anchors());
15400            } else {
15401                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15402            }
15403
15404            cx.emit(EditorEvent::Edited { transaction_id });
15405            Some(transaction_id)
15406        } else {
15407            None
15408        }
15409    }
15410
15411    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15412        if self.selection_mark_mode {
15413            self.change_selections(None, window, cx, |s| {
15414                s.move_with(|_, sel| {
15415                    sel.collapse_to(sel.head(), SelectionGoal::None);
15416                });
15417            })
15418        }
15419        self.selection_mark_mode = true;
15420        cx.notify();
15421    }
15422
15423    pub fn swap_selection_ends(
15424        &mut self,
15425        _: &actions::SwapSelectionEnds,
15426        window: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) {
15429        self.change_selections(None, window, cx, |s| {
15430            s.move_with(|_, sel| {
15431                if sel.start != sel.end {
15432                    sel.reversed = !sel.reversed
15433                }
15434            });
15435        });
15436        self.request_autoscroll(Autoscroll::newest(), cx);
15437        cx.notify();
15438    }
15439
15440    pub fn toggle_fold(
15441        &mut self,
15442        _: &actions::ToggleFold,
15443        window: &mut Window,
15444        cx: &mut Context<Self>,
15445    ) {
15446        if self.is_singleton(cx) {
15447            let selection = self.selections.newest::<Point>(cx);
15448
15449            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15450            let range = if selection.is_empty() {
15451                let point = selection.head().to_display_point(&display_map);
15452                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15453                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15454                    .to_point(&display_map);
15455                start..end
15456            } else {
15457                selection.range()
15458            };
15459            if display_map.folds_in_range(range).next().is_some() {
15460                self.unfold_lines(&Default::default(), window, cx)
15461            } else {
15462                self.fold(&Default::default(), window, cx)
15463            }
15464        } else {
15465            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15466            let buffer_ids: HashSet<_> = self
15467                .selections
15468                .disjoint_anchor_ranges()
15469                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15470                .collect();
15471
15472            let should_unfold = buffer_ids
15473                .iter()
15474                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15475
15476            for buffer_id in buffer_ids {
15477                if should_unfold {
15478                    self.unfold_buffer(buffer_id, cx);
15479                } else {
15480                    self.fold_buffer(buffer_id, cx);
15481                }
15482            }
15483        }
15484    }
15485
15486    pub fn toggle_fold_recursive(
15487        &mut self,
15488        _: &actions::ToggleFoldRecursive,
15489        window: &mut Window,
15490        cx: &mut Context<Self>,
15491    ) {
15492        let selection = self.selections.newest::<Point>(cx);
15493
15494        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15495        let range = if selection.is_empty() {
15496            let point = selection.head().to_display_point(&display_map);
15497            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15498            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15499                .to_point(&display_map);
15500            start..end
15501        } else {
15502            selection.range()
15503        };
15504        if display_map.folds_in_range(range).next().is_some() {
15505            self.unfold_recursive(&Default::default(), window, cx)
15506        } else {
15507            self.fold_recursive(&Default::default(), window, cx)
15508        }
15509    }
15510
15511    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15512        if self.is_singleton(cx) {
15513            let mut to_fold = Vec::new();
15514            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15515            let selections = self.selections.all_adjusted(cx);
15516
15517            for selection in selections {
15518                let range = selection.range().sorted();
15519                let buffer_start_row = range.start.row;
15520
15521                if range.start.row != range.end.row {
15522                    let mut found = false;
15523                    let mut row = range.start.row;
15524                    while row <= range.end.row {
15525                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15526                        {
15527                            found = true;
15528                            row = crease.range().end.row + 1;
15529                            to_fold.push(crease);
15530                        } else {
15531                            row += 1
15532                        }
15533                    }
15534                    if found {
15535                        continue;
15536                    }
15537                }
15538
15539                for row in (0..=range.start.row).rev() {
15540                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15541                        if crease.range().end.row >= buffer_start_row {
15542                            to_fold.push(crease);
15543                            if row <= range.start.row {
15544                                break;
15545                            }
15546                        }
15547                    }
15548                }
15549            }
15550
15551            self.fold_creases(to_fold, true, window, cx);
15552        } else {
15553            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15554            let buffer_ids = self
15555                .selections
15556                .disjoint_anchor_ranges()
15557                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15558                .collect::<HashSet<_>>();
15559            for buffer_id in buffer_ids {
15560                self.fold_buffer(buffer_id, cx);
15561            }
15562        }
15563    }
15564
15565    fn fold_at_level(
15566        &mut self,
15567        fold_at: &FoldAtLevel,
15568        window: &mut Window,
15569        cx: &mut Context<Self>,
15570    ) {
15571        if !self.buffer.read(cx).is_singleton() {
15572            return;
15573        }
15574
15575        let fold_at_level = fold_at.0;
15576        let snapshot = self.buffer.read(cx).snapshot(cx);
15577        let mut to_fold = Vec::new();
15578        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15579
15580        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15581            while start_row < end_row {
15582                match self
15583                    .snapshot(window, cx)
15584                    .crease_for_buffer_row(MultiBufferRow(start_row))
15585                {
15586                    Some(crease) => {
15587                        let nested_start_row = crease.range().start.row + 1;
15588                        let nested_end_row = crease.range().end.row;
15589
15590                        if current_level < fold_at_level {
15591                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15592                        } else if current_level == fold_at_level {
15593                            to_fold.push(crease);
15594                        }
15595
15596                        start_row = nested_end_row + 1;
15597                    }
15598                    None => start_row += 1,
15599                }
15600            }
15601        }
15602
15603        self.fold_creases(to_fold, true, window, cx);
15604    }
15605
15606    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15607        if self.buffer.read(cx).is_singleton() {
15608            let mut fold_ranges = Vec::new();
15609            let snapshot = self.buffer.read(cx).snapshot(cx);
15610
15611            for row in 0..snapshot.max_row().0 {
15612                if let Some(foldable_range) = self
15613                    .snapshot(window, cx)
15614                    .crease_for_buffer_row(MultiBufferRow(row))
15615                {
15616                    fold_ranges.push(foldable_range);
15617                }
15618            }
15619
15620            self.fold_creases(fold_ranges, true, window, cx);
15621        } else {
15622            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15623                editor
15624                    .update_in(cx, |editor, _, cx| {
15625                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15626                            editor.fold_buffer(buffer_id, cx);
15627                        }
15628                    })
15629                    .ok();
15630            });
15631        }
15632    }
15633
15634    pub fn fold_function_bodies(
15635        &mut self,
15636        _: &actions::FoldFunctionBodies,
15637        window: &mut Window,
15638        cx: &mut Context<Self>,
15639    ) {
15640        let snapshot = self.buffer.read(cx).snapshot(cx);
15641
15642        let ranges = snapshot
15643            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15644            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15645            .collect::<Vec<_>>();
15646
15647        let creases = ranges
15648            .into_iter()
15649            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15650            .collect();
15651
15652        self.fold_creases(creases, true, window, cx);
15653    }
15654
15655    pub fn fold_recursive(
15656        &mut self,
15657        _: &actions::FoldRecursive,
15658        window: &mut Window,
15659        cx: &mut Context<Self>,
15660    ) {
15661        let mut to_fold = Vec::new();
15662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15663        let selections = self.selections.all_adjusted(cx);
15664
15665        for selection in selections {
15666            let range = selection.range().sorted();
15667            let buffer_start_row = range.start.row;
15668
15669            if range.start.row != range.end.row {
15670                let mut found = false;
15671                for row in range.start.row..=range.end.row {
15672                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15673                        found = true;
15674                        to_fold.push(crease);
15675                    }
15676                }
15677                if found {
15678                    continue;
15679                }
15680            }
15681
15682            for row in (0..=range.start.row).rev() {
15683                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15684                    if crease.range().end.row >= buffer_start_row {
15685                        to_fold.push(crease);
15686                    } else {
15687                        break;
15688                    }
15689                }
15690            }
15691        }
15692
15693        self.fold_creases(to_fold, true, window, cx);
15694    }
15695
15696    pub fn fold_at(
15697        &mut self,
15698        buffer_row: MultiBufferRow,
15699        window: &mut Window,
15700        cx: &mut Context<Self>,
15701    ) {
15702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15703
15704        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15705            let autoscroll = self
15706                .selections
15707                .all::<Point>(cx)
15708                .iter()
15709                .any(|selection| crease.range().overlaps(&selection.range()));
15710
15711            self.fold_creases(vec![crease], autoscroll, window, cx);
15712        }
15713    }
15714
15715    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15716        if self.is_singleton(cx) {
15717            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15718            let buffer = &display_map.buffer_snapshot;
15719            let selections = self.selections.all::<Point>(cx);
15720            let ranges = selections
15721                .iter()
15722                .map(|s| {
15723                    let range = s.display_range(&display_map).sorted();
15724                    let mut start = range.start.to_point(&display_map);
15725                    let mut end = range.end.to_point(&display_map);
15726                    start.column = 0;
15727                    end.column = buffer.line_len(MultiBufferRow(end.row));
15728                    start..end
15729                })
15730                .collect::<Vec<_>>();
15731
15732            self.unfold_ranges(&ranges, true, true, cx);
15733        } else {
15734            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15735            let buffer_ids = self
15736                .selections
15737                .disjoint_anchor_ranges()
15738                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15739                .collect::<HashSet<_>>();
15740            for buffer_id in buffer_ids {
15741                self.unfold_buffer(buffer_id, cx);
15742            }
15743        }
15744    }
15745
15746    pub fn unfold_recursive(
15747        &mut self,
15748        _: &UnfoldRecursive,
15749        _window: &mut Window,
15750        cx: &mut Context<Self>,
15751    ) {
15752        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15753        let selections = self.selections.all::<Point>(cx);
15754        let ranges = selections
15755            .iter()
15756            .map(|s| {
15757                let mut range = s.display_range(&display_map).sorted();
15758                *range.start.column_mut() = 0;
15759                *range.end.column_mut() = display_map.line_len(range.end.row());
15760                let start = range.start.to_point(&display_map);
15761                let end = range.end.to_point(&display_map);
15762                start..end
15763            })
15764            .collect::<Vec<_>>();
15765
15766        self.unfold_ranges(&ranges, true, true, cx);
15767    }
15768
15769    pub fn unfold_at(
15770        &mut self,
15771        buffer_row: MultiBufferRow,
15772        _window: &mut Window,
15773        cx: &mut Context<Self>,
15774    ) {
15775        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15776
15777        let intersection_range = Point::new(buffer_row.0, 0)
15778            ..Point::new(
15779                buffer_row.0,
15780                display_map.buffer_snapshot.line_len(buffer_row),
15781            );
15782
15783        let autoscroll = self
15784            .selections
15785            .all::<Point>(cx)
15786            .iter()
15787            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15788
15789        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15790    }
15791
15792    pub fn unfold_all(
15793        &mut self,
15794        _: &actions::UnfoldAll,
15795        _window: &mut Window,
15796        cx: &mut Context<Self>,
15797    ) {
15798        if self.buffer.read(cx).is_singleton() {
15799            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15800            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15801        } else {
15802            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15803                editor
15804                    .update(cx, |editor, cx| {
15805                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15806                            editor.unfold_buffer(buffer_id, cx);
15807                        }
15808                    })
15809                    .ok();
15810            });
15811        }
15812    }
15813
15814    pub fn fold_selected_ranges(
15815        &mut self,
15816        _: &FoldSelectedRanges,
15817        window: &mut Window,
15818        cx: &mut Context<Self>,
15819    ) {
15820        let selections = self.selections.all_adjusted(cx);
15821        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15822        let ranges = selections
15823            .into_iter()
15824            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15825            .collect::<Vec<_>>();
15826        self.fold_creases(ranges, true, window, cx);
15827    }
15828
15829    pub fn fold_ranges<T: ToOffset + Clone>(
15830        &mut self,
15831        ranges: Vec<Range<T>>,
15832        auto_scroll: bool,
15833        window: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15837        let ranges = ranges
15838            .into_iter()
15839            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15840            .collect::<Vec<_>>();
15841        self.fold_creases(ranges, auto_scroll, window, cx);
15842    }
15843
15844    pub fn fold_creases<T: ToOffset + Clone>(
15845        &mut self,
15846        creases: Vec<Crease<T>>,
15847        auto_scroll: bool,
15848        _window: &mut Window,
15849        cx: &mut Context<Self>,
15850    ) {
15851        if creases.is_empty() {
15852            return;
15853        }
15854
15855        let mut buffers_affected = HashSet::default();
15856        let multi_buffer = self.buffer().read(cx);
15857        for crease in &creases {
15858            if let Some((_, buffer, _)) =
15859                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
15860            {
15861                buffers_affected.insert(buffer.read(cx).remote_id());
15862            };
15863        }
15864
15865        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
15866
15867        if auto_scroll {
15868            self.request_autoscroll(Autoscroll::fit(), cx);
15869        }
15870
15871        cx.notify();
15872
15873        self.scrollbar_marker_state.dirty = true;
15874        self.folds_did_change(cx);
15875    }
15876
15877    /// Removes any folds whose ranges intersect any of the given ranges.
15878    pub fn unfold_ranges<T: ToOffset + Clone>(
15879        &mut self,
15880        ranges: &[Range<T>],
15881        inclusive: bool,
15882        auto_scroll: bool,
15883        cx: &mut Context<Self>,
15884    ) {
15885        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15886            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
15887        });
15888        self.folds_did_change(cx);
15889    }
15890
15891    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15892        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
15893            return;
15894        }
15895        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15896        self.display_map.update(cx, |display_map, cx| {
15897            display_map.fold_buffers([buffer_id], cx)
15898        });
15899        cx.emit(EditorEvent::BufferFoldToggled {
15900            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
15901            folded: true,
15902        });
15903        cx.notify();
15904    }
15905
15906    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15907        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
15908            return;
15909        }
15910        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15911        self.display_map.update(cx, |display_map, cx| {
15912            display_map.unfold_buffers([buffer_id], cx);
15913        });
15914        cx.emit(EditorEvent::BufferFoldToggled {
15915            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
15916            folded: false,
15917        });
15918        cx.notify();
15919    }
15920
15921    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
15922        self.display_map.read(cx).is_buffer_folded(buffer)
15923    }
15924
15925    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
15926        self.display_map.read(cx).folded_buffers()
15927    }
15928
15929    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15930        self.display_map.update(cx, |display_map, cx| {
15931            display_map.disable_header_for_buffer(buffer_id, cx);
15932        });
15933        cx.notify();
15934    }
15935
15936    /// Removes any folds with the given ranges.
15937    pub fn remove_folds_with_type<T: ToOffset + Clone>(
15938        &mut self,
15939        ranges: &[Range<T>],
15940        type_id: TypeId,
15941        auto_scroll: bool,
15942        cx: &mut Context<Self>,
15943    ) {
15944        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15945            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
15946        });
15947        self.folds_did_change(cx);
15948    }
15949
15950    fn remove_folds_with<T: ToOffset + Clone>(
15951        &mut self,
15952        ranges: &[Range<T>],
15953        auto_scroll: bool,
15954        cx: &mut Context<Self>,
15955        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
15956    ) {
15957        if ranges.is_empty() {
15958            return;
15959        }
15960
15961        let mut buffers_affected = HashSet::default();
15962        let multi_buffer = self.buffer().read(cx);
15963        for range in ranges {
15964            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
15965                buffers_affected.insert(buffer.read(cx).remote_id());
15966            };
15967        }
15968
15969        self.display_map.update(cx, update);
15970
15971        if auto_scroll {
15972            self.request_autoscroll(Autoscroll::fit(), cx);
15973        }
15974
15975        cx.notify();
15976        self.scrollbar_marker_state.dirty = true;
15977        self.active_indent_guides_state.dirty = true;
15978    }
15979
15980    pub fn update_fold_widths(
15981        &mut self,
15982        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
15983        cx: &mut Context<Self>,
15984    ) -> bool {
15985        self.display_map
15986            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
15987    }
15988
15989    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
15990        self.display_map.read(cx).fold_placeholder.clone()
15991    }
15992
15993    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
15994        self.buffer.update(cx, |buffer, cx| {
15995            buffer.set_all_diff_hunks_expanded(cx);
15996        });
15997    }
15998
15999    pub fn expand_all_diff_hunks(
16000        &mut self,
16001        _: &ExpandAllDiffHunks,
16002        _window: &mut Window,
16003        cx: &mut Context<Self>,
16004    ) {
16005        self.buffer.update(cx, |buffer, cx| {
16006            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16007        });
16008    }
16009
16010    pub fn toggle_selected_diff_hunks(
16011        &mut self,
16012        _: &ToggleSelectedDiffHunks,
16013        _window: &mut Window,
16014        cx: &mut Context<Self>,
16015    ) {
16016        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16017        self.toggle_diff_hunks_in_ranges(ranges, cx);
16018    }
16019
16020    pub fn diff_hunks_in_ranges<'a>(
16021        &'a self,
16022        ranges: &'a [Range<Anchor>],
16023        buffer: &'a MultiBufferSnapshot,
16024    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16025        ranges.iter().flat_map(move |range| {
16026            let end_excerpt_id = range.end.excerpt_id;
16027            let range = range.to_point(buffer);
16028            let mut peek_end = range.end;
16029            if range.end.row < buffer.max_row().0 {
16030                peek_end = Point::new(range.end.row + 1, 0);
16031            }
16032            buffer
16033                .diff_hunks_in_range(range.start..peek_end)
16034                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16035        })
16036    }
16037
16038    pub fn has_stageable_diff_hunks_in_ranges(
16039        &self,
16040        ranges: &[Range<Anchor>],
16041        snapshot: &MultiBufferSnapshot,
16042    ) -> bool {
16043        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16044        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16045    }
16046
16047    pub fn toggle_staged_selected_diff_hunks(
16048        &mut self,
16049        _: &::git::ToggleStaged,
16050        _: &mut Window,
16051        cx: &mut Context<Self>,
16052    ) {
16053        let snapshot = self.buffer.read(cx).snapshot(cx);
16054        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16055        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16056        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16057    }
16058
16059    pub fn set_render_diff_hunk_controls(
16060        &mut self,
16061        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16062        cx: &mut Context<Self>,
16063    ) {
16064        self.render_diff_hunk_controls = render_diff_hunk_controls;
16065        cx.notify();
16066    }
16067
16068    pub fn stage_and_next(
16069        &mut self,
16070        _: &::git::StageAndNext,
16071        window: &mut Window,
16072        cx: &mut Context<Self>,
16073    ) {
16074        self.do_stage_or_unstage_and_next(true, window, cx);
16075    }
16076
16077    pub fn unstage_and_next(
16078        &mut self,
16079        _: &::git::UnstageAndNext,
16080        window: &mut Window,
16081        cx: &mut Context<Self>,
16082    ) {
16083        self.do_stage_or_unstage_and_next(false, window, cx);
16084    }
16085
16086    pub fn stage_or_unstage_diff_hunks(
16087        &mut self,
16088        stage: bool,
16089        ranges: Vec<Range<Anchor>>,
16090        cx: &mut Context<Self>,
16091    ) {
16092        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16093        cx.spawn(async move |this, cx| {
16094            task.await?;
16095            this.update(cx, |this, cx| {
16096                let snapshot = this.buffer.read(cx).snapshot(cx);
16097                let chunk_by = this
16098                    .diff_hunks_in_ranges(&ranges, &snapshot)
16099                    .chunk_by(|hunk| hunk.buffer_id);
16100                for (buffer_id, hunks) in &chunk_by {
16101                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16102                }
16103            })
16104        })
16105        .detach_and_log_err(cx);
16106    }
16107
16108    fn save_buffers_for_ranges_if_needed(
16109        &mut self,
16110        ranges: &[Range<Anchor>],
16111        cx: &mut Context<Editor>,
16112    ) -> Task<Result<()>> {
16113        let multibuffer = self.buffer.read(cx);
16114        let snapshot = multibuffer.read(cx);
16115        let buffer_ids: HashSet<_> = ranges
16116            .iter()
16117            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16118            .collect();
16119        drop(snapshot);
16120
16121        let mut buffers = HashSet::default();
16122        for buffer_id in buffer_ids {
16123            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16124                let buffer = buffer_entity.read(cx);
16125                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16126                {
16127                    buffers.insert(buffer_entity);
16128                }
16129            }
16130        }
16131
16132        if let Some(project) = &self.project {
16133            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16134        } else {
16135            Task::ready(Ok(()))
16136        }
16137    }
16138
16139    fn do_stage_or_unstage_and_next(
16140        &mut self,
16141        stage: bool,
16142        window: &mut Window,
16143        cx: &mut Context<Self>,
16144    ) {
16145        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16146
16147        if ranges.iter().any(|range| range.start != range.end) {
16148            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16149            return;
16150        }
16151
16152        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16153        let snapshot = self.snapshot(window, cx);
16154        let position = self.selections.newest::<Point>(cx).head();
16155        let mut row = snapshot
16156            .buffer_snapshot
16157            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16158            .find(|hunk| hunk.row_range.start.0 > position.row)
16159            .map(|hunk| hunk.row_range.start);
16160
16161        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16162        // Outside of the project diff editor, wrap around to the beginning.
16163        if !all_diff_hunks_expanded {
16164            row = row.or_else(|| {
16165                snapshot
16166                    .buffer_snapshot
16167                    .diff_hunks_in_range(Point::zero()..position)
16168                    .find(|hunk| hunk.row_range.end.0 < position.row)
16169                    .map(|hunk| hunk.row_range.start)
16170            });
16171        }
16172
16173        if let Some(row) = row {
16174            let destination = Point::new(row.0, 0);
16175            let autoscroll = Autoscroll::center();
16176
16177            self.unfold_ranges(&[destination..destination], false, false, cx);
16178            self.change_selections(Some(autoscroll), window, cx, |s| {
16179                s.select_ranges([destination..destination]);
16180            });
16181        }
16182    }
16183
16184    fn do_stage_or_unstage(
16185        &self,
16186        stage: bool,
16187        buffer_id: BufferId,
16188        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16189        cx: &mut App,
16190    ) -> Option<()> {
16191        let project = self.project.as_ref()?;
16192        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16193        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16194        let buffer_snapshot = buffer.read(cx).snapshot();
16195        let file_exists = buffer_snapshot
16196            .file()
16197            .is_some_and(|file| file.disk_state().exists());
16198        diff.update(cx, |diff, cx| {
16199            diff.stage_or_unstage_hunks(
16200                stage,
16201                &hunks
16202                    .map(|hunk| buffer_diff::DiffHunk {
16203                        buffer_range: hunk.buffer_range,
16204                        diff_base_byte_range: hunk.diff_base_byte_range,
16205                        secondary_status: hunk.secondary_status,
16206                        range: Point::zero()..Point::zero(), // unused
16207                    })
16208                    .collect::<Vec<_>>(),
16209                &buffer_snapshot,
16210                file_exists,
16211                cx,
16212            )
16213        });
16214        None
16215    }
16216
16217    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16218        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16219        self.buffer
16220            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16221    }
16222
16223    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16224        self.buffer.update(cx, |buffer, cx| {
16225            let ranges = vec![Anchor::min()..Anchor::max()];
16226            if !buffer.all_diff_hunks_expanded()
16227                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16228            {
16229                buffer.collapse_diff_hunks(ranges, cx);
16230                true
16231            } else {
16232                false
16233            }
16234        })
16235    }
16236
16237    fn toggle_diff_hunks_in_ranges(
16238        &mut self,
16239        ranges: Vec<Range<Anchor>>,
16240        cx: &mut Context<Editor>,
16241    ) {
16242        self.buffer.update(cx, |buffer, cx| {
16243            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16244            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16245        })
16246    }
16247
16248    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16249        self.buffer.update(cx, |buffer, cx| {
16250            let snapshot = buffer.snapshot(cx);
16251            let excerpt_id = range.end.excerpt_id;
16252            let point_range = range.to_point(&snapshot);
16253            let expand = !buffer.single_hunk_is_expanded(range, cx);
16254            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16255        })
16256    }
16257
16258    pub(crate) fn apply_all_diff_hunks(
16259        &mut self,
16260        _: &ApplyAllDiffHunks,
16261        window: &mut Window,
16262        cx: &mut Context<Self>,
16263    ) {
16264        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16265
16266        let buffers = self.buffer.read(cx).all_buffers();
16267        for branch_buffer in buffers {
16268            branch_buffer.update(cx, |branch_buffer, cx| {
16269                branch_buffer.merge_into_base(Vec::new(), cx);
16270            });
16271        }
16272
16273        if let Some(project) = self.project.clone() {
16274            self.save(true, project, window, cx).detach_and_log_err(cx);
16275        }
16276    }
16277
16278    pub(crate) fn apply_selected_diff_hunks(
16279        &mut self,
16280        _: &ApplyDiffHunk,
16281        window: &mut Window,
16282        cx: &mut Context<Self>,
16283    ) {
16284        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16285        let snapshot = self.snapshot(window, cx);
16286        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16287        let mut ranges_by_buffer = HashMap::default();
16288        self.transact(window, cx, |editor, _window, cx| {
16289            for hunk in hunks {
16290                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16291                    ranges_by_buffer
16292                        .entry(buffer.clone())
16293                        .or_insert_with(Vec::new)
16294                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16295                }
16296            }
16297
16298            for (buffer, ranges) in ranges_by_buffer {
16299                buffer.update(cx, |buffer, cx| {
16300                    buffer.merge_into_base(ranges, cx);
16301                });
16302            }
16303        });
16304
16305        if let Some(project) = self.project.clone() {
16306            self.save(true, project, window, cx).detach_and_log_err(cx);
16307        }
16308    }
16309
16310    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16311        if hovered != self.gutter_hovered {
16312            self.gutter_hovered = hovered;
16313            cx.notify();
16314        }
16315    }
16316
16317    pub fn insert_blocks(
16318        &mut self,
16319        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16320        autoscroll: Option<Autoscroll>,
16321        cx: &mut Context<Self>,
16322    ) -> Vec<CustomBlockId> {
16323        let blocks = self
16324            .display_map
16325            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16326        if let Some(autoscroll) = autoscroll {
16327            self.request_autoscroll(autoscroll, cx);
16328        }
16329        cx.notify();
16330        blocks
16331    }
16332
16333    pub fn resize_blocks(
16334        &mut self,
16335        heights: HashMap<CustomBlockId, u32>,
16336        autoscroll: Option<Autoscroll>,
16337        cx: &mut Context<Self>,
16338    ) {
16339        self.display_map
16340            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16341        if let Some(autoscroll) = autoscroll {
16342            self.request_autoscroll(autoscroll, cx);
16343        }
16344        cx.notify();
16345    }
16346
16347    pub fn replace_blocks(
16348        &mut self,
16349        renderers: HashMap<CustomBlockId, RenderBlock>,
16350        autoscroll: Option<Autoscroll>,
16351        cx: &mut Context<Self>,
16352    ) {
16353        self.display_map
16354            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16355        if let Some(autoscroll) = autoscroll {
16356            self.request_autoscroll(autoscroll, cx);
16357        }
16358        cx.notify();
16359    }
16360
16361    pub fn remove_blocks(
16362        &mut self,
16363        block_ids: HashSet<CustomBlockId>,
16364        autoscroll: Option<Autoscroll>,
16365        cx: &mut Context<Self>,
16366    ) {
16367        self.display_map.update(cx, |display_map, cx| {
16368            display_map.remove_blocks(block_ids, cx)
16369        });
16370        if let Some(autoscroll) = autoscroll {
16371            self.request_autoscroll(autoscroll, cx);
16372        }
16373        cx.notify();
16374    }
16375
16376    pub fn row_for_block(
16377        &self,
16378        block_id: CustomBlockId,
16379        cx: &mut Context<Self>,
16380    ) -> Option<DisplayRow> {
16381        self.display_map
16382            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16383    }
16384
16385    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16386        self.focused_block = Some(focused_block);
16387    }
16388
16389    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16390        self.focused_block.take()
16391    }
16392
16393    pub fn insert_creases(
16394        &mut self,
16395        creases: impl IntoIterator<Item = Crease<Anchor>>,
16396        cx: &mut Context<Self>,
16397    ) -> Vec<CreaseId> {
16398        self.display_map
16399            .update(cx, |map, cx| map.insert_creases(creases, cx))
16400    }
16401
16402    pub fn remove_creases(
16403        &mut self,
16404        ids: impl IntoIterator<Item = CreaseId>,
16405        cx: &mut Context<Self>,
16406    ) -> Vec<(CreaseId, Range<Anchor>)> {
16407        self.display_map
16408            .update(cx, |map, cx| map.remove_creases(ids, cx))
16409    }
16410
16411    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16412        self.display_map
16413            .update(cx, |map, cx| map.snapshot(cx))
16414            .longest_row()
16415    }
16416
16417    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16418        self.display_map
16419            .update(cx, |map, cx| map.snapshot(cx))
16420            .max_point()
16421    }
16422
16423    pub fn text(&self, cx: &App) -> String {
16424        self.buffer.read(cx).read(cx).text()
16425    }
16426
16427    pub fn is_empty(&self, cx: &App) -> bool {
16428        self.buffer.read(cx).read(cx).is_empty()
16429    }
16430
16431    pub fn text_option(&self, cx: &App) -> Option<String> {
16432        let text = self.text(cx);
16433        let text = text.trim();
16434
16435        if text.is_empty() {
16436            return None;
16437        }
16438
16439        Some(text.to_string())
16440    }
16441
16442    pub fn set_text(
16443        &mut self,
16444        text: impl Into<Arc<str>>,
16445        window: &mut Window,
16446        cx: &mut Context<Self>,
16447    ) {
16448        self.transact(window, cx, |this, _, cx| {
16449            this.buffer
16450                .read(cx)
16451                .as_singleton()
16452                .expect("you can only call set_text on editors for singleton buffers")
16453                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16454        });
16455    }
16456
16457    pub fn display_text(&self, cx: &mut App) -> String {
16458        self.display_map
16459            .update(cx, |map, cx| map.snapshot(cx))
16460            .text()
16461    }
16462
16463    fn create_minimap(
16464        &self,
16465        minimap_settings: MinimapSettings,
16466        window: &mut Window,
16467        cx: &mut Context<Self>,
16468    ) -> Option<Entity<Self>> {
16469        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16470            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16471    }
16472
16473    fn initialize_new_minimap(
16474        &self,
16475        minimap_settings: MinimapSettings,
16476        window: &mut Window,
16477        cx: &mut Context<Self>,
16478    ) -> Entity<Self> {
16479        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16480
16481        let mut minimap = Editor::new_internal(
16482            EditorMode::Minimap {
16483                parent: cx.weak_entity(),
16484            },
16485            self.buffer.clone(),
16486            self.project.clone(),
16487            Some(self.display_map.clone()),
16488            window,
16489            cx,
16490        );
16491        minimap.scroll_manager.clone_state(&self.scroll_manager);
16492        minimap.set_text_style_refinement(TextStyleRefinement {
16493            font_size: Some(MINIMAP_FONT_SIZE),
16494            font_weight: Some(MINIMAP_FONT_WEIGHT),
16495            ..Default::default()
16496        });
16497        minimap.update_minimap_configuration(minimap_settings, cx);
16498        cx.new(|_| minimap)
16499    }
16500
16501    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16502        let current_line_highlight = minimap_settings
16503            .current_line_highlight
16504            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16505        self.set_current_line_highlight(Some(current_line_highlight));
16506    }
16507
16508    pub fn minimap(&self) -> Option<&Entity<Self>> {
16509        self.minimap
16510            .as_ref()
16511            .filter(|_| self.minimap_visibility.visible())
16512    }
16513
16514    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16515        let mut wrap_guides = smallvec::smallvec![];
16516
16517        if self.show_wrap_guides == Some(false) {
16518            return wrap_guides;
16519        }
16520
16521        let settings = self.buffer.read(cx).language_settings(cx);
16522        if settings.show_wrap_guides {
16523            match self.soft_wrap_mode(cx) {
16524                SoftWrap::Column(soft_wrap) => {
16525                    wrap_guides.push((soft_wrap as usize, true));
16526                }
16527                SoftWrap::Bounded(soft_wrap) => {
16528                    wrap_guides.push((soft_wrap as usize, true));
16529                }
16530                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16531            }
16532            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16533        }
16534
16535        wrap_guides
16536    }
16537
16538    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16539        let settings = self.buffer.read(cx).language_settings(cx);
16540        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16541        match mode {
16542            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16543                SoftWrap::None
16544            }
16545            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16546            language_settings::SoftWrap::PreferredLineLength => {
16547                SoftWrap::Column(settings.preferred_line_length)
16548            }
16549            language_settings::SoftWrap::Bounded => {
16550                SoftWrap::Bounded(settings.preferred_line_length)
16551            }
16552        }
16553    }
16554
16555    pub fn set_soft_wrap_mode(
16556        &mut self,
16557        mode: language_settings::SoftWrap,
16558
16559        cx: &mut Context<Self>,
16560    ) {
16561        self.soft_wrap_mode_override = Some(mode);
16562        cx.notify();
16563    }
16564
16565    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16566        self.hard_wrap = hard_wrap;
16567        cx.notify();
16568    }
16569
16570    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16571        self.text_style_refinement = Some(style);
16572    }
16573
16574    /// called by the Element so we know what style we were most recently rendered with.
16575    pub(crate) fn set_style(
16576        &mut self,
16577        style: EditorStyle,
16578        window: &mut Window,
16579        cx: &mut Context<Self>,
16580    ) {
16581        // We intentionally do not inform the display map about the minimap style
16582        // so that wrapping is not recalculated and stays consistent for the editor
16583        // and its linked minimap.
16584        if !self.mode.is_minimap() {
16585            let rem_size = window.rem_size();
16586            self.display_map.update(cx, |map, cx| {
16587                map.set_font(
16588                    style.text.font(),
16589                    style.text.font_size.to_pixels(rem_size),
16590                    cx,
16591                )
16592            });
16593        }
16594        self.style = Some(style);
16595    }
16596
16597    pub fn style(&self) -> Option<&EditorStyle> {
16598        self.style.as_ref()
16599    }
16600
16601    // Called by the element. This method is not designed to be called outside of the editor
16602    // element's layout code because it does not notify when rewrapping is computed synchronously.
16603    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16604        self.display_map
16605            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16606    }
16607
16608    pub fn set_soft_wrap(&mut self) {
16609        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16610    }
16611
16612    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16613        if self.soft_wrap_mode_override.is_some() {
16614            self.soft_wrap_mode_override.take();
16615        } else {
16616            let soft_wrap = match self.soft_wrap_mode(cx) {
16617                SoftWrap::GitDiff => return,
16618                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16619                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16620                    language_settings::SoftWrap::None
16621                }
16622            };
16623            self.soft_wrap_mode_override = Some(soft_wrap);
16624        }
16625        cx.notify();
16626    }
16627
16628    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16629        let Some(workspace) = self.workspace() else {
16630            return;
16631        };
16632        let fs = workspace.read(cx).app_state().fs.clone();
16633        let current_show = TabBarSettings::get_global(cx).show;
16634        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16635            setting.show = Some(!current_show);
16636        });
16637    }
16638
16639    pub fn toggle_indent_guides(
16640        &mut self,
16641        _: &ToggleIndentGuides,
16642        _: &mut Window,
16643        cx: &mut Context<Self>,
16644    ) {
16645        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16646            self.buffer
16647                .read(cx)
16648                .language_settings(cx)
16649                .indent_guides
16650                .enabled
16651        });
16652        self.show_indent_guides = Some(!currently_enabled);
16653        cx.notify();
16654    }
16655
16656    fn should_show_indent_guides(&self) -> Option<bool> {
16657        self.show_indent_guides
16658    }
16659
16660    pub fn toggle_line_numbers(
16661        &mut self,
16662        _: &ToggleLineNumbers,
16663        _: &mut Window,
16664        cx: &mut Context<Self>,
16665    ) {
16666        let mut editor_settings = EditorSettings::get_global(cx).clone();
16667        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16668        EditorSettings::override_global(editor_settings, cx);
16669    }
16670
16671    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16672        if let Some(show_line_numbers) = self.show_line_numbers {
16673            return show_line_numbers;
16674        }
16675        EditorSettings::get_global(cx).gutter.line_numbers
16676    }
16677
16678    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16679        self.use_relative_line_numbers
16680            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16681    }
16682
16683    pub fn toggle_relative_line_numbers(
16684        &mut self,
16685        _: &ToggleRelativeLineNumbers,
16686        _: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) {
16689        let is_relative = self.should_use_relative_line_numbers(cx);
16690        self.set_relative_line_number(Some(!is_relative), cx)
16691    }
16692
16693    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16694        self.use_relative_line_numbers = is_relative;
16695        cx.notify();
16696    }
16697
16698    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16699        self.show_gutter = show_gutter;
16700        cx.notify();
16701    }
16702
16703    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16704        self.show_scrollbars = show_scrollbars;
16705        cx.notify();
16706    }
16707
16708    pub fn set_minimap_visibility(
16709        &mut self,
16710        minimap_visibility: MinimapVisibility,
16711        window: &mut Window,
16712        cx: &mut Context<Self>,
16713    ) {
16714        if self.minimap_visibility != minimap_visibility {
16715            if minimap_visibility.visible() && self.minimap.is_none() {
16716                let minimap_settings = EditorSettings::get_global(cx).minimap;
16717                self.minimap =
16718                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16719            }
16720            self.minimap_visibility = minimap_visibility;
16721            cx.notify();
16722        }
16723    }
16724
16725    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16726        self.set_show_scrollbars(false, cx);
16727        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16728    }
16729
16730    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16731        self.show_line_numbers = Some(show_line_numbers);
16732        cx.notify();
16733    }
16734
16735    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16736        self.disable_expand_excerpt_buttons = true;
16737        cx.notify();
16738    }
16739
16740    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16741        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16742        cx.notify();
16743    }
16744
16745    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16746        self.show_code_actions = Some(show_code_actions);
16747        cx.notify();
16748    }
16749
16750    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16751        self.show_runnables = Some(show_runnables);
16752        cx.notify();
16753    }
16754
16755    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16756        self.show_breakpoints = Some(show_breakpoints);
16757        cx.notify();
16758    }
16759
16760    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16761        if self.display_map.read(cx).masked != masked {
16762            self.display_map.update(cx, |map, _| map.masked = masked);
16763        }
16764        cx.notify()
16765    }
16766
16767    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16768        self.show_wrap_guides = Some(show_wrap_guides);
16769        cx.notify();
16770    }
16771
16772    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16773        self.show_indent_guides = Some(show_indent_guides);
16774        cx.notify();
16775    }
16776
16777    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16778        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16779            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16780                if let Some(dir) = file.abs_path(cx).parent() {
16781                    return Some(dir.to_owned());
16782                }
16783            }
16784
16785            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16786                return Some(project_path.path.to_path_buf());
16787            }
16788        }
16789
16790        None
16791    }
16792
16793    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16794        self.active_excerpt(cx)?
16795            .1
16796            .read(cx)
16797            .file()
16798            .and_then(|f| f.as_local())
16799    }
16800
16801    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16802        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16803            let buffer = buffer.read(cx);
16804            if let Some(project_path) = buffer.project_path(cx) {
16805                let project = self.project.as_ref()?.read(cx);
16806                project.absolute_path(&project_path, cx)
16807            } else {
16808                buffer
16809                    .file()
16810                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16811            }
16812        })
16813    }
16814
16815    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16816        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16817            let project_path = buffer.read(cx).project_path(cx)?;
16818            let project = self.project.as_ref()?.read(cx);
16819            let entry = project.entry_for_path(&project_path, cx)?;
16820            let path = entry.path.to_path_buf();
16821            Some(path)
16822        })
16823    }
16824
16825    pub fn reveal_in_finder(
16826        &mut self,
16827        _: &RevealInFileManager,
16828        _window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) {
16831        if let Some(target) = self.target_file(cx) {
16832            cx.reveal_path(&target.abs_path(cx));
16833        }
16834    }
16835
16836    pub fn copy_path(
16837        &mut self,
16838        _: &zed_actions::workspace::CopyPath,
16839        _window: &mut Window,
16840        cx: &mut Context<Self>,
16841    ) {
16842        if let Some(path) = self.target_file_abs_path(cx) {
16843            if let Some(path) = path.to_str() {
16844                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16845            }
16846        }
16847    }
16848
16849    pub fn copy_relative_path(
16850        &mut self,
16851        _: &zed_actions::workspace::CopyRelativePath,
16852        _window: &mut Window,
16853        cx: &mut Context<Self>,
16854    ) {
16855        if let Some(path) = self.target_file_path(cx) {
16856            if let Some(path) = path.to_str() {
16857                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16858            }
16859        }
16860    }
16861
16862    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
16863        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
16864            buffer.read(cx).project_path(cx)
16865        } else {
16866            None
16867        }
16868    }
16869
16870    // Returns true if the editor handled a go-to-line request
16871    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
16872        maybe!({
16873            let breakpoint_store = self.breakpoint_store.as_ref()?;
16874
16875            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
16876            else {
16877                self.clear_row_highlights::<ActiveDebugLine>();
16878                return None;
16879            };
16880
16881            let position = active_stack_frame.position;
16882            let buffer_id = position.buffer_id?;
16883            let snapshot = self
16884                .project
16885                .as_ref()?
16886                .read(cx)
16887                .buffer_for_id(buffer_id, cx)?
16888                .read(cx)
16889                .snapshot();
16890
16891            let mut handled = false;
16892            for (id, ExcerptRange { context, .. }) in
16893                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
16894            {
16895                if context.start.cmp(&position, &snapshot).is_ge()
16896                    || context.end.cmp(&position, &snapshot).is_lt()
16897                {
16898                    continue;
16899                }
16900                let snapshot = self.buffer.read(cx).snapshot(cx);
16901                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
16902
16903                handled = true;
16904                self.clear_row_highlights::<ActiveDebugLine>();
16905
16906                self.go_to_line::<ActiveDebugLine>(
16907                    multibuffer_anchor,
16908                    Some(cx.theme().colors().editor_debugger_active_line_background),
16909                    window,
16910                    cx,
16911                );
16912
16913                cx.notify();
16914            }
16915
16916            handled.then_some(())
16917        })
16918        .is_some()
16919    }
16920
16921    pub fn copy_file_name_without_extension(
16922        &mut self,
16923        _: &CopyFileNameWithoutExtension,
16924        _: &mut Window,
16925        cx: &mut Context<Self>,
16926    ) {
16927        if let Some(file) = self.target_file(cx) {
16928            if let Some(file_stem) = file.path().file_stem() {
16929                if let Some(name) = file_stem.to_str() {
16930                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16931                }
16932            }
16933        }
16934    }
16935
16936    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
16937        if let Some(file) = self.target_file(cx) {
16938            if let Some(file_name) = file.path().file_name() {
16939                if let Some(name) = file_name.to_str() {
16940                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16941                }
16942            }
16943        }
16944    }
16945
16946    pub fn toggle_git_blame(
16947        &mut self,
16948        _: &::git::Blame,
16949        window: &mut Window,
16950        cx: &mut Context<Self>,
16951    ) {
16952        self.show_git_blame_gutter = !self.show_git_blame_gutter;
16953
16954        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
16955            self.start_git_blame(true, window, cx);
16956        }
16957
16958        cx.notify();
16959    }
16960
16961    pub fn toggle_git_blame_inline(
16962        &mut self,
16963        _: &ToggleGitBlameInline,
16964        window: &mut Window,
16965        cx: &mut Context<Self>,
16966    ) {
16967        self.toggle_git_blame_inline_internal(true, window, cx);
16968        cx.notify();
16969    }
16970
16971    pub fn open_git_blame_commit(
16972        &mut self,
16973        _: &OpenGitBlameCommit,
16974        window: &mut Window,
16975        cx: &mut Context<Self>,
16976    ) {
16977        self.open_git_blame_commit_internal(window, cx);
16978    }
16979
16980    fn open_git_blame_commit_internal(
16981        &mut self,
16982        window: &mut Window,
16983        cx: &mut Context<Self>,
16984    ) -> Option<()> {
16985        let blame = self.blame.as_ref()?;
16986        let snapshot = self.snapshot(window, cx);
16987        let cursor = self.selections.newest::<Point>(cx).head();
16988        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
16989        let blame_entry = blame
16990            .update(cx, |blame, cx| {
16991                blame
16992                    .blame_for_rows(
16993                        &[RowInfo {
16994                            buffer_id: Some(buffer.remote_id()),
16995                            buffer_row: Some(point.row),
16996                            ..Default::default()
16997                        }],
16998                        cx,
16999                    )
17000                    .next()
17001            })
17002            .flatten()?;
17003        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17004        let repo = blame.read(cx).repository(cx)?;
17005        let workspace = self.workspace()?.downgrade();
17006        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17007        None
17008    }
17009
17010    pub fn git_blame_inline_enabled(&self) -> bool {
17011        self.git_blame_inline_enabled
17012    }
17013
17014    pub fn toggle_selection_menu(
17015        &mut self,
17016        _: &ToggleSelectionMenu,
17017        _: &mut Window,
17018        cx: &mut Context<Self>,
17019    ) {
17020        self.show_selection_menu = self
17021            .show_selection_menu
17022            .map(|show_selections_menu| !show_selections_menu)
17023            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17024
17025        cx.notify();
17026    }
17027
17028    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17029        self.show_selection_menu
17030            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17031    }
17032
17033    fn start_git_blame(
17034        &mut self,
17035        user_triggered: bool,
17036        window: &mut Window,
17037        cx: &mut Context<Self>,
17038    ) {
17039        if let Some(project) = self.project.as_ref() {
17040            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17041                return;
17042            };
17043
17044            if buffer.read(cx).file().is_none() {
17045                return;
17046            }
17047
17048            let focused = self.focus_handle(cx).contains_focused(window, cx);
17049
17050            let project = project.clone();
17051            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17052            self.blame_subscription =
17053                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17054            self.blame = Some(blame);
17055        }
17056    }
17057
17058    fn toggle_git_blame_inline_internal(
17059        &mut self,
17060        user_triggered: bool,
17061        window: &mut Window,
17062        cx: &mut Context<Self>,
17063    ) {
17064        if self.git_blame_inline_enabled {
17065            self.git_blame_inline_enabled = false;
17066            self.show_git_blame_inline = false;
17067            self.show_git_blame_inline_delay_task.take();
17068        } else {
17069            self.git_blame_inline_enabled = true;
17070            self.start_git_blame_inline(user_triggered, window, cx);
17071        }
17072
17073        cx.notify();
17074    }
17075
17076    fn start_git_blame_inline(
17077        &mut self,
17078        user_triggered: bool,
17079        window: &mut Window,
17080        cx: &mut Context<Self>,
17081    ) {
17082        self.start_git_blame(user_triggered, window, cx);
17083
17084        if ProjectSettings::get_global(cx)
17085            .git
17086            .inline_blame_delay()
17087            .is_some()
17088        {
17089            self.start_inline_blame_timer(window, cx);
17090        } else {
17091            self.show_git_blame_inline = true
17092        }
17093    }
17094
17095    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17096        self.blame.as_ref()
17097    }
17098
17099    pub fn show_git_blame_gutter(&self) -> bool {
17100        self.show_git_blame_gutter
17101    }
17102
17103    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17104        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17105    }
17106
17107    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17108        self.show_git_blame_inline
17109            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17110            && !self.newest_selection_head_on_empty_line(cx)
17111            && self.has_blame_entries(cx)
17112    }
17113
17114    fn has_blame_entries(&self, cx: &App) -> bool {
17115        self.blame()
17116            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17117    }
17118
17119    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17120        let cursor_anchor = self.selections.newest_anchor().head();
17121
17122        let snapshot = self.buffer.read(cx).snapshot(cx);
17123        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17124
17125        snapshot.line_len(buffer_row) == 0
17126    }
17127
17128    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17129        let buffer_and_selection = maybe!({
17130            let selection = self.selections.newest::<Point>(cx);
17131            let selection_range = selection.range();
17132
17133            let multi_buffer = self.buffer().read(cx);
17134            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17135            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17136
17137            let (buffer, range, _) = if selection.reversed {
17138                buffer_ranges.first()
17139            } else {
17140                buffer_ranges.last()
17141            }?;
17142
17143            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17144                ..text::ToPoint::to_point(&range.end, &buffer).row;
17145            Some((
17146                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17147                selection,
17148            ))
17149        });
17150
17151        let Some((buffer, selection)) = buffer_and_selection else {
17152            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17153        };
17154
17155        let Some(project) = self.project.as_ref() else {
17156            return Task::ready(Err(anyhow!("editor does not have project")));
17157        };
17158
17159        project.update(cx, |project, cx| {
17160            project.get_permalink_to_line(&buffer, selection, cx)
17161        })
17162    }
17163
17164    pub fn copy_permalink_to_line(
17165        &mut self,
17166        _: &CopyPermalinkToLine,
17167        window: &mut Window,
17168        cx: &mut Context<Self>,
17169    ) {
17170        let permalink_task = self.get_permalink_to_line(cx);
17171        let workspace = self.workspace();
17172
17173        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17174            Ok(permalink) => {
17175                cx.update(|_, cx| {
17176                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17177                })
17178                .ok();
17179            }
17180            Err(err) => {
17181                let message = format!("Failed to copy permalink: {err}");
17182
17183                Err::<(), anyhow::Error>(err).log_err();
17184
17185                if let Some(workspace) = workspace {
17186                    workspace
17187                        .update_in(cx, |workspace, _, cx| {
17188                            struct CopyPermalinkToLine;
17189
17190                            workspace.show_toast(
17191                                Toast::new(
17192                                    NotificationId::unique::<CopyPermalinkToLine>(),
17193                                    message,
17194                                ),
17195                                cx,
17196                            )
17197                        })
17198                        .ok();
17199                }
17200            }
17201        })
17202        .detach();
17203    }
17204
17205    pub fn copy_file_location(
17206        &mut self,
17207        _: &CopyFileLocation,
17208        _: &mut Window,
17209        cx: &mut Context<Self>,
17210    ) {
17211        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17212        if let Some(file) = self.target_file(cx) {
17213            if let Some(path) = file.path().to_str() {
17214                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17215            }
17216        }
17217    }
17218
17219    pub fn open_permalink_to_line(
17220        &mut self,
17221        _: &OpenPermalinkToLine,
17222        window: &mut Window,
17223        cx: &mut Context<Self>,
17224    ) {
17225        let permalink_task = self.get_permalink_to_line(cx);
17226        let workspace = self.workspace();
17227
17228        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17229            Ok(permalink) => {
17230                cx.update(|_, cx| {
17231                    cx.open_url(permalink.as_ref());
17232                })
17233                .ok();
17234            }
17235            Err(err) => {
17236                let message = format!("Failed to open permalink: {err}");
17237
17238                Err::<(), anyhow::Error>(err).log_err();
17239
17240                if let Some(workspace) = workspace {
17241                    workspace
17242                        .update(cx, |workspace, cx| {
17243                            struct OpenPermalinkToLine;
17244
17245                            workspace.show_toast(
17246                                Toast::new(
17247                                    NotificationId::unique::<OpenPermalinkToLine>(),
17248                                    message,
17249                                ),
17250                                cx,
17251                            )
17252                        })
17253                        .ok();
17254                }
17255            }
17256        })
17257        .detach();
17258    }
17259
17260    pub fn insert_uuid_v4(
17261        &mut self,
17262        _: &InsertUuidV4,
17263        window: &mut Window,
17264        cx: &mut Context<Self>,
17265    ) {
17266        self.insert_uuid(UuidVersion::V4, window, cx);
17267    }
17268
17269    pub fn insert_uuid_v7(
17270        &mut self,
17271        _: &InsertUuidV7,
17272        window: &mut Window,
17273        cx: &mut Context<Self>,
17274    ) {
17275        self.insert_uuid(UuidVersion::V7, window, cx);
17276    }
17277
17278    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17279        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17280        self.transact(window, cx, |this, window, cx| {
17281            let edits = this
17282                .selections
17283                .all::<Point>(cx)
17284                .into_iter()
17285                .map(|selection| {
17286                    let uuid = match version {
17287                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17288                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17289                    };
17290
17291                    (selection.range(), uuid.to_string())
17292                });
17293            this.edit(edits, cx);
17294            this.refresh_inline_completion(true, false, window, cx);
17295        });
17296    }
17297
17298    pub fn open_selections_in_multibuffer(
17299        &mut self,
17300        _: &OpenSelectionsInMultibuffer,
17301        window: &mut Window,
17302        cx: &mut Context<Self>,
17303    ) {
17304        let multibuffer = self.buffer.read(cx);
17305
17306        let Some(buffer) = multibuffer.as_singleton() else {
17307            return;
17308        };
17309
17310        let Some(workspace) = self.workspace() else {
17311            return;
17312        };
17313
17314        let locations = self
17315            .selections
17316            .disjoint_anchors()
17317            .iter()
17318            .map(|range| Location {
17319                buffer: buffer.clone(),
17320                range: range.start.text_anchor..range.end.text_anchor,
17321            })
17322            .collect::<Vec<_>>();
17323
17324        let title = multibuffer.title(cx).to_string();
17325
17326        cx.spawn_in(window, async move |_, cx| {
17327            workspace.update_in(cx, |workspace, window, cx| {
17328                Self::open_locations_in_multibuffer(
17329                    workspace,
17330                    locations,
17331                    format!("Selections for '{title}'"),
17332                    false,
17333                    MultibufferSelectionMode::All,
17334                    window,
17335                    cx,
17336                );
17337            })
17338        })
17339        .detach();
17340    }
17341
17342    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17343    /// last highlight added will be used.
17344    ///
17345    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17346    pub fn highlight_rows<T: 'static>(
17347        &mut self,
17348        range: Range<Anchor>,
17349        color: Hsla,
17350        options: RowHighlightOptions,
17351        cx: &mut Context<Self>,
17352    ) {
17353        let snapshot = self.buffer().read(cx).snapshot(cx);
17354        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17355        let ix = row_highlights.binary_search_by(|highlight| {
17356            Ordering::Equal
17357                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17358                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17359        });
17360
17361        if let Err(mut ix) = ix {
17362            let index = post_inc(&mut self.highlight_order);
17363
17364            // If this range intersects with the preceding highlight, then merge it with
17365            // the preceding highlight. Otherwise insert a new highlight.
17366            let mut merged = false;
17367            if ix > 0 {
17368                let prev_highlight = &mut row_highlights[ix - 1];
17369                if prev_highlight
17370                    .range
17371                    .end
17372                    .cmp(&range.start, &snapshot)
17373                    .is_ge()
17374                {
17375                    ix -= 1;
17376                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17377                        prev_highlight.range.end = range.end;
17378                    }
17379                    merged = true;
17380                    prev_highlight.index = index;
17381                    prev_highlight.color = color;
17382                    prev_highlight.options = options;
17383                }
17384            }
17385
17386            if !merged {
17387                row_highlights.insert(
17388                    ix,
17389                    RowHighlight {
17390                        range: range.clone(),
17391                        index,
17392                        color,
17393                        options,
17394                        type_id: TypeId::of::<T>(),
17395                    },
17396                );
17397            }
17398
17399            // If any of the following highlights intersect with this one, merge them.
17400            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17401                let highlight = &row_highlights[ix];
17402                if next_highlight
17403                    .range
17404                    .start
17405                    .cmp(&highlight.range.end, &snapshot)
17406                    .is_le()
17407                {
17408                    if next_highlight
17409                        .range
17410                        .end
17411                        .cmp(&highlight.range.end, &snapshot)
17412                        .is_gt()
17413                    {
17414                        row_highlights[ix].range.end = next_highlight.range.end;
17415                    }
17416                    row_highlights.remove(ix + 1);
17417                } else {
17418                    break;
17419                }
17420            }
17421        }
17422    }
17423
17424    /// Remove any highlighted row ranges of the given type that intersect the
17425    /// given ranges.
17426    pub fn remove_highlighted_rows<T: 'static>(
17427        &mut self,
17428        ranges_to_remove: Vec<Range<Anchor>>,
17429        cx: &mut Context<Self>,
17430    ) {
17431        let snapshot = self.buffer().read(cx).snapshot(cx);
17432        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17433        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17434        row_highlights.retain(|highlight| {
17435            while let Some(range_to_remove) = ranges_to_remove.peek() {
17436                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17437                    Ordering::Less | Ordering::Equal => {
17438                        ranges_to_remove.next();
17439                    }
17440                    Ordering::Greater => {
17441                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17442                            Ordering::Less | Ordering::Equal => {
17443                                return false;
17444                            }
17445                            Ordering::Greater => break,
17446                        }
17447                    }
17448                }
17449            }
17450
17451            true
17452        })
17453    }
17454
17455    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17456    pub fn clear_row_highlights<T: 'static>(&mut self) {
17457        self.highlighted_rows.remove(&TypeId::of::<T>());
17458    }
17459
17460    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17461    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17462        self.highlighted_rows
17463            .get(&TypeId::of::<T>())
17464            .map_or(&[] as &[_], |vec| vec.as_slice())
17465            .iter()
17466            .map(|highlight| (highlight.range.clone(), highlight.color))
17467    }
17468
17469    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17470    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17471    /// Allows to ignore certain kinds of highlights.
17472    pub fn highlighted_display_rows(
17473        &self,
17474        window: &mut Window,
17475        cx: &mut App,
17476    ) -> BTreeMap<DisplayRow, LineHighlight> {
17477        let snapshot = self.snapshot(window, cx);
17478        let mut used_highlight_orders = HashMap::default();
17479        self.highlighted_rows
17480            .iter()
17481            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17482            .fold(
17483                BTreeMap::<DisplayRow, LineHighlight>::new(),
17484                |mut unique_rows, highlight| {
17485                    let start = highlight.range.start.to_display_point(&snapshot);
17486                    let end = highlight.range.end.to_display_point(&snapshot);
17487                    let start_row = start.row().0;
17488                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17489                        && end.column() == 0
17490                    {
17491                        end.row().0.saturating_sub(1)
17492                    } else {
17493                        end.row().0
17494                    };
17495                    for row in start_row..=end_row {
17496                        let used_index =
17497                            used_highlight_orders.entry(row).or_insert(highlight.index);
17498                        if highlight.index >= *used_index {
17499                            *used_index = highlight.index;
17500                            unique_rows.insert(
17501                                DisplayRow(row),
17502                                LineHighlight {
17503                                    include_gutter: highlight.options.include_gutter,
17504                                    border: None,
17505                                    background: highlight.color.into(),
17506                                    type_id: Some(highlight.type_id),
17507                                },
17508                            );
17509                        }
17510                    }
17511                    unique_rows
17512                },
17513            )
17514    }
17515
17516    pub fn highlighted_display_row_for_autoscroll(
17517        &self,
17518        snapshot: &DisplaySnapshot,
17519    ) -> Option<DisplayRow> {
17520        self.highlighted_rows
17521            .values()
17522            .flat_map(|highlighted_rows| highlighted_rows.iter())
17523            .filter_map(|highlight| {
17524                if highlight.options.autoscroll {
17525                    Some(highlight.range.start.to_display_point(snapshot).row())
17526                } else {
17527                    None
17528                }
17529            })
17530            .min()
17531    }
17532
17533    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17534        self.highlight_background::<SearchWithinRange>(
17535            ranges,
17536            |colors| colors.editor_document_highlight_read_background,
17537            cx,
17538        )
17539    }
17540
17541    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17542        self.breadcrumb_header = Some(new_header);
17543    }
17544
17545    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17546        self.clear_background_highlights::<SearchWithinRange>(cx);
17547    }
17548
17549    pub fn highlight_background<T: 'static>(
17550        &mut self,
17551        ranges: &[Range<Anchor>],
17552        color_fetcher: fn(&ThemeColors) -> Hsla,
17553        cx: &mut Context<Self>,
17554    ) {
17555        self.background_highlights
17556            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17557        self.scrollbar_marker_state.dirty = true;
17558        cx.notify();
17559    }
17560
17561    pub fn clear_background_highlights<T: 'static>(
17562        &mut self,
17563        cx: &mut Context<Self>,
17564    ) -> Option<BackgroundHighlight> {
17565        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17566        if !text_highlights.1.is_empty() {
17567            self.scrollbar_marker_state.dirty = true;
17568            cx.notify();
17569        }
17570        Some(text_highlights)
17571    }
17572
17573    pub fn highlight_gutter<T: 'static>(
17574        &mut self,
17575        ranges: &[Range<Anchor>],
17576        color_fetcher: fn(&App) -> Hsla,
17577        cx: &mut Context<Self>,
17578    ) {
17579        self.gutter_highlights
17580            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17581        cx.notify();
17582    }
17583
17584    pub fn clear_gutter_highlights<T: 'static>(
17585        &mut self,
17586        cx: &mut Context<Self>,
17587    ) -> Option<GutterHighlight> {
17588        cx.notify();
17589        self.gutter_highlights.remove(&TypeId::of::<T>())
17590    }
17591
17592    #[cfg(feature = "test-support")]
17593    pub fn all_text_background_highlights(
17594        &self,
17595        window: &mut Window,
17596        cx: &mut Context<Self>,
17597    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17598        let snapshot = self.snapshot(window, cx);
17599        let buffer = &snapshot.buffer_snapshot;
17600        let start = buffer.anchor_before(0);
17601        let end = buffer.anchor_after(buffer.len());
17602        let theme = cx.theme().colors();
17603        self.background_highlights_in_range(start..end, &snapshot, theme)
17604    }
17605
17606    #[cfg(feature = "test-support")]
17607    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17608        let snapshot = self.buffer().read(cx).snapshot(cx);
17609
17610        let highlights = self
17611            .background_highlights
17612            .get(&TypeId::of::<items::BufferSearchHighlights>());
17613
17614        if let Some((_color, ranges)) = highlights {
17615            ranges
17616                .iter()
17617                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17618                .collect_vec()
17619        } else {
17620            vec![]
17621        }
17622    }
17623
17624    fn document_highlights_for_position<'a>(
17625        &'a self,
17626        position: Anchor,
17627        buffer: &'a MultiBufferSnapshot,
17628    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17629        let read_highlights = self
17630            .background_highlights
17631            .get(&TypeId::of::<DocumentHighlightRead>())
17632            .map(|h| &h.1);
17633        let write_highlights = self
17634            .background_highlights
17635            .get(&TypeId::of::<DocumentHighlightWrite>())
17636            .map(|h| &h.1);
17637        let left_position = position.bias_left(buffer);
17638        let right_position = position.bias_right(buffer);
17639        read_highlights
17640            .into_iter()
17641            .chain(write_highlights)
17642            .flat_map(move |ranges| {
17643                let start_ix = match ranges.binary_search_by(|probe| {
17644                    let cmp = probe.end.cmp(&left_position, buffer);
17645                    if cmp.is_ge() {
17646                        Ordering::Greater
17647                    } else {
17648                        Ordering::Less
17649                    }
17650                }) {
17651                    Ok(i) | Err(i) => i,
17652                };
17653
17654                ranges[start_ix..]
17655                    .iter()
17656                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17657            })
17658    }
17659
17660    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17661        self.background_highlights
17662            .get(&TypeId::of::<T>())
17663            .map_or(false, |(_, highlights)| !highlights.is_empty())
17664    }
17665
17666    pub fn background_highlights_in_range(
17667        &self,
17668        search_range: Range<Anchor>,
17669        display_snapshot: &DisplaySnapshot,
17670        theme: &ThemeColors,
17671    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17672        let mut results = Vec::new();
17673        for (color_fetcher, ranges) in self.background_highlights.values() {
17674            let color = color_fetcher(theme);
17675            let start_ix = match ranges.binary_search_by(|probe| {
17676                let cmp = probe
17677                    .end
17678                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17679                if cmp.is_gt() {
17680                    Ordering::Greater
17681                } else {
17682                    Ordering::Less
17683                }
17684            }) {
17685                Ok(i) | Err(i) => i,
17686            };
17687            for range in &ranges[start_ix..] {
17688                if range
17689                    .start
17690                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17691                    .is_ge()
17692                {
17693                    break;
17694                }
17695
17696                let start = range.start.to_display_point(display_snapshot);
17697                let end = range.end.to_display_point(display_snapshot);
17698                results.push((start..end, color))
17699            }
17700        }
17701        results
17702    }
17703
17704    pub fn background_highlight_row_ranges<T: 'static>(
17705        &self,
17706        search_range: Range<Anchor>,
17707        display_snapshot: &DisplaySnapshot,
17708        count: usize,
17709    ) -> Vec<RangeInclusive<DisplayPoint>> {
17710        let mut results = Vec::new();
17711        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17712            return vec![];
17713        };
17714
17715        let start_ix = match ranges.binary_search_by(|probe| {
17716            let cmp = probe
17717                .end
17718                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17719            if cmp.is_gt() {
17720                Ordering::Greater
17721            } else {
17722                Ordering::Less
17723            }
17724        }) {
17725            Ok(i) | Err(i) => i,
17726        };
17727        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17728            if let (Some(start_display), Some(end_display)) = (start, end) {
17729                results.push(
17730                    start_display.to_display_point(display_snapshot)
17731                        ..=end_display.to_display_point(display_snapshot),
17732                );
17733            }
17734        };
17735        let mut start_row: Option<Point> = None;
17736        let mut end_row: Option<Point> = None;
17737        if ranges.len() > count {
17738            return Vec::new();
17739        }
17740        for range in &ranges[start_ix..] {
17741            if range
17742                .start
17743                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17744                .is_ge()
17745            {
17746                break;
17747            }
17748            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17749            if let Some(current_row) = &end_row {
17750                if end.row == current_row.row {
17751                    continue;
17752                }
17753            }
17754            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17755            if start_row.is_none() {
17756                assert_eq!(end_row, None);
17757                start_row = Some(start);
17758                end_row = Some(end);
17759                continue;
17760            }
17761            if let Some(current_end) = end_row.as_mut() {
17762                if start.row > current_end.row + 1 {
17763                    push_region(start_row, end_row);
17764                    start_row = Some(start);
17765                    end_row = Some(end);
17766                } else {
17767                    // Merge two hunks.
17768                    *current_end = end;
17769                }
17770            } else {
17771                unreachable!();
17772            }
17773        }
17774        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17775        push_region(start_row, end_row);
17776        results
17777    }
17778
17779    pub fn gutter_highlights_in_range(
17780        &self,
17781        search_range: Range<Anchor>,
17782        display_snapshot: &DisplaySnapshot,
17783        cx: &App,
17784    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17785        let mut results = Vec::new();
17786        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17787            let color = color_fetcher(cx);
17788            let start_ix = match ranges.binary_search_by(|probe| {
17789                let cmp = probe
17790                    .end
17791                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17792                if cmp.is_gt() {
17793                    Ordering::Greater
17794                } else {
17795                    Ordering::Less
17796                }
17797            }) {
17798                Ok(i) | Err(i) => i,
17799            };
17800            for range in &ranges[start_ix..] {
17801                if range
17802                    .start
17803                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17804                    .is_ge()
17805                {
17806                    break;
17807                }
17808
17809                let start = range.start.to_display_point(display_snapshot);
17810                let end = range.end.to_display_point(display_snapshot);
17811                results.push((start..end, color))
17812            }
17813        }
17814        results
17815    }
17816
17817    /// Get the text ranges corresponding to the redaction query
17818    pub fn redacted_ranges(
17819        &self,
17820        search_range: Range<Anchor>,
17821        display_snapshot: &DisplaySnapshot,
17822        cx: &App,
17823    ) -> Vec<Range<DisplayPoint>> {
17824        display_snapshot
17825            .buffer_snapshot
17826            .redacted_ranges(search_range, |file| {
17827                if let Some(file) = file {
17828                    file.is_private()
17829                        && EditorSettings::get(
17830                            Some(SettingsLocation {
17831                                worktree_id: file.worktree_id(cx),
17832                                path: file.path().as_ref(),
17833                            }),
17834                            cx,
17835                        )
17836                        .redact_private_values
17837                } else {
17838                    false
17839                }
17840            })
17841            .map(|range| {
17842                range.start.to_display_point(display_snapshot)
17843                    ..range.end.to_display_point(display_snapshot)
17844            })
17845            .collect()
17846    }
17847
17848    pub fn highlight_text<T: 'static>(
17849        &mut self,
17850        ranges: Vec<Range<Anchor>>,
17851        style: HighlightStyle,
17852        cx: &mut Context<Self>,
17853    ) {
17854        self.display_map.update(cx, |map, _| {
17855            map.highlight_text(TypeId::of::<T>(), ranges, style)
17856        });
17857        cx.notify();
17858    }
17859
17860    pub(crate) fn highlight_inlays<T: 'static>(
17861        &mut self,
17862        highlights: Vec<InlayHighlight>,
17863        style: HighlightStyle,
17864        cx: &mut Context<Self>,
17865    ) {
17866        self.display_map.update(cx, |map, _| {
17867            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
17868        });
17869        cx.notify();
17870    }
17871
17872    pub fn text_highlights<'a, T: 'static>(
17873        &'a self,
17874        cx: &'a App,
17875    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
17876        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
17877    }
17878
17879    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
17880        let cleared = self
17881            .display_map
17882            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
17883        if cleared {
17884            cx.notify();
17885        }
17886    }
17887
17888    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
17889        (self.read_only(cx) || self.blink_manager.read(cx).visible())
17890            && self.focus_handle.is_focused(window)
17891    }
17892
17893    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
17894        self.show_cursor_when_unfocused = is_enabled;
17895        cx.notify();
17896    }
17897
17898    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
17899        cx.notify();
17900    }
17901
17902    fn on_debug_session_event(
17903        &mut self,
17904        _session: Entity<Session>,
17905        event: &SessionEvent,
17906        cx: &mut Context<Self>,
17907    ) {
17908        match event {
17909            SessionEvent::InvalidateInlineValue => {
17910                self.refresh_inline_values(cx);
17911            }
17912            _ => {}
17913        }
17914    }
17915
17916    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
17917        let Some(project) = self.project.clone() else {
17918            return;
17919        };
17920
17921        if !self.inline_value_cache.enabled {
17922            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
17923            self.splice_inlays(&inlays, Vec::new(), cx);
17924            return;
17925        }
17926
17927        let current_execution_position = self
17928            .highlighted_rows
17929            .get(&TypeId::of::<ActiveDebugLine>())
17930            .and_then(|lines| lines.last().map(|line| line.range.start));
17931
17932        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
17933            let inline_values = editor
17934                .update(cx, |editor, cx| {
17935                    let Some(current_execution_position) = current_execution_position else {
17936                        return Some(Task::ready(Ok(Vec::new())));
17937                    };
17938
17939                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
17940                        let snapshot = buffer.snapshot(cx);
17941
17942                        let excerpt = snapshot.excerpt_containing(
17943                            current_execution_position..current_execution_position,
17944                        )?;
17945
17946                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
17947                    })?;
17948
17949                    let range =
17950                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
17951
17952                    project.inline_values(buffer, range, cx)
17953                })
17954                .ok()
17955                .flatten()?
17956                .await
17957                .context("refreshing debugger inlays")
17958                .log_err()?;
17959
17960            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
17961
17962            for (buffer_id, inline_value) in inline_values
17963                .into_iter()
17964                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
17965            {
17966                buffer_inline_values
17967                    .entry(buffer_id)
17968                    .or_default()
17969                    .push(inline_value);
17970            }
17971
17972            editor
17973                .update(cx, |editor, cx| {
17974                    let snapshot = editor.buffer.read(cx).snapshot(cx);
17975                    let mut new_inlays = Vec::default();
17976
17977                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
17978                        let buffer_id = buffer_snapshot.remote_id();
17979                        buffer_inline_values
17980                            .get(&buffer_id)
17981                            .into_iter()
17982                            .flatten()
17983                            .for_each(|hint| {
17984                                let inlay = Inlay::debugger_hint(
17985                                    post_inc(&mut editor.next_inlay_id),
17986                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
17987                                    hint.text(),
17988                                );
17989
17990                                new_inlays.push(inlay);
17991                            });
17992                    }
17993
17994                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
17995                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
17996
17997                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
17998                })
17999                .ok()?;
18000            Some(())
18001        });
18002    }
18003
18004    fn on_buffer_event(
18005        &mut self,
18006        multibuffer: &Entity<MultiBuffer>,
18007        event: &multi_buffer::Event,
18008        window: &mut Window,
18009        cx: &mut Context<Self>,
18010    ) {
18011        match event {
18012            multi_buffer::Event::Edited {
18013                singleton_buffer_edited,
18014                edited_buffer: buffer_edited,
18015            } => {
18016                self.scrollbar_marker_state.dirty = true;
18017                self.active_indent_guides_state.dirty = true;
18018                self.refresh_active_diagnostics(cx);
18019                self.refresh_code_actions(window, cx);
18020                self.refresh_selected_text_highlights(true, window, cx);
18021                refresh_matching_bracket_highlights(self, window, cx);
18022                if self.has_active_inline_completion() {
18023                    self.update_visible_inline_completion(window, cx);
18024                }
18025                if let Some(buffer) = buffer_edited {
18026                    let buffer_id = buffer.read(cx).remote_id();
18027                    if !self.registered_buffers.contains_key(&buffer_id) {
18028                        if let Some(project) = self.project.as_ref() {
18029                            project.update(cx, |project, cx| {
18030                                self.registered_buffers.insert(
18031                                    buffer_id,
18032                                    project.register_buffer_with_language_servers(&buffer, cx),
18033                                );
18034                            })
18035                        }
18036                    }
18037                }
18038                cx.emit(EditorEvent::BufferEdited);
18039                cx.emit(SearchEvent::MatchesInvalidated);
18040                if *singleton_buffer_edited {
18041                    if let Some(project) = &self.project {
18042                        #[allow(clippy::mutable_key_type)]
18043                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18044                            multibuffer
18045                                .all_buffers()
18046                                .into_iter()
18047                                .filter_map(|buffer| {
18048                                    buffer.update(cx, |buffer, cx| {
18049                                        let language = buffer.language()?;
18050                                        let should_discard = project.update(cx, |project, cx| {
18051                                            project.is_local()
18052                                                && !project.has_language_servers_for(buffer, cx)
18053                                        });
18054                                        should_discard.not().then_some(language.clone())
18055                                    })
18056                                })
18057                                .collect::<HashSet<_>>()
18058                        });
18059                        if !languages_affected.is_empty() {
18060                            self.refresh_inlay_hints(
18061                                InlayHintRefreshReason::BufferEdited(languages_affected),
18062                                cx,
18063                            );
18064                        }
18065                    }
18066                }
18067
18068                let Some(project) = &self.project else { return };
18069                let (telemetry, is_via_ssh) = {
18070                    let project = project.read(cx);
18071                    let telemetry = project.client().telemetry().clone();
18072                    let is_via_ssh = project.is_via_ssh();
18073                    (telemetry, is_via_ssh)
18074                };
18075                refresh_linked_ranges(self, window, cx);
18076                telemetry.log_edit_event("editor", is_via_ssh);
18077            }
18078            multi_buffer::Event::ExcerptsAdded {
18079                buffer,
18080                predecessor,
18081                excerpts,
18082            } => {
18083                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18084                let buffer_id = buffer.read(cx).remote_id();
18085                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18086                    if let Some(project) = &self.project {
18087                        update_uncommitted_diff_for_buffer(
18088                            cx.entity(),
18089                            project,
18090                            [buffer.clone()],
18091                            self.buffer.clone(),
18092                            cx,
18093                        )
18094                        .detach();
18095                    }
18096                }
18097                cx.emit(EditorEvent::ExcerptsAdded {
18098                    buffer: buffer.clone(),
18099                    predecessor: *predecessor,
18100                    excerpts: excerpts.clone(),
18101                });
18102                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18103            }
18104            multi_buffer::Event::ExcerptsRemoved {
18105                ids,
18106                removed_buffer_ids,
18107            } => {
18108                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18109                let buffer = self.buffer.read(cx);
18110                self.registered_buffers
18111                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18112                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18113                cx.emit(EditorEvent::ExcerptsRemoved {
18114                    ids: ids.clone(),
18115                    removed_buffer_ids: removed_buffer_ids.clone(),
18116                })
18117            }
18118            multi_buffer::Event::ExcerptsEdited {
18119                excerpt_ids,
18120                buffer_ids,
18121            } => {
18122                self.display_map.update(cx, |map, cx| {
18123                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18124                });
18125                cx.emit(EditorEvent::ExcerptsEdited {
18126                    ids: excerpt_ids.clone(),
18127                })
18128            }
18129            multi_buffer::Event::ExcerptsExpanded { ids } => {
18130                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18131                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18132            }
18133            multi_buffer::Event::Reparsed(buffer_id) => {
18134                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18135                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18136
18137                cx.emit(EditorEvent::Reparsed(*buffer_id));
18138            }
18139            multi_buffer::Event::DiffHunksToggled => {
18140                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18141            }
18142            multi_buffer::Event::LanguageChanged(buffer_id) => {
18143                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18144                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18145                cx.emit(EditorEvent::Reparsed(*buffer_id));
18146                cx.notify();
18147            }
18148            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18149            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18150            multi_buffer::Event::FileHandleChanged
18151            | multi_buffer::Event::Reloaded
18152            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18153            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18154            multi_buffer::Event::DiagnosticsUpdated => {
18155                self.refresh_active_diagnostics(cx);
18156                self.refresh_inline_diagnostics(true, window, cx);
18157                self.scrollbar_marker_state.dirty = true;
18158                cx.notify();
18159            }
18160            _ => {}
18161        };
18162    }
18163
18164    pub fn start_temporary_diff_override(&mut self) {
18165        self.load_diff_task.take();
18166        self.temporary_diff_override = true;
18167    }
18168
18169    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18170        self.temporary_diff_override = false;
18171        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18172        self.buffer.update(cx, |buffer, cx| {
18173            buffer.set_all_diff_hunks_collapsed(cx);
18174        });
18175
18176        if let Some(project) = self.project.clone() {
18177            self.load_diff_task = Some(
18178                update_uncommitted_diff_for_buffer(
18179                    cx.entity(),
18180                    &project,
18181                    self.buffer.read(cx).all_buffers(),
18182                    self.buffer.clone(),
18183                    cx,
18184                )
18185                .shared(),
18186            );
18187        }
18188    }
18189
18190    fn on_display_map_changed(
18191        &mut self,
18192        _: Entity<DisplayMap>,
18193        _: &mut Window,
18194        cx: &mut Context<Self>,
18195    ) {
18196        cx.notify();
18197    }
18198
18199    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18200        let new_severity = if self.diagnostics_enabled() {
18201            EditorSettings::get_global(cx)
18202                .diagnostics_max_severity
18203                .unwrap_or(DiagnosticSeverity::Hint)
18204        } else {
18205            DiagnosticSeverity::Off
18206        };
18207        self.set_max_diagnostics_severity(new_severity, cx);
18208        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18209        self.update_edit_prediction_settings(cx);
18210        self.refresh_inline_completion(true, false, window, cx);
18211        self.refresh_inlay_hints(
18212            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18213                self.selections.newest_anchor().head(),
18214                &self.buffer.read(cx).snapshot(cx),
18215                cx,
18216            )),
18217            cx,
18218        );
18219
18220        let old_cursor_shape = self.cursor_shape;
18221
18222        {
18223            let editor_settings = EditorSettings::get_global(cx);
18224            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18225            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18226            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18227            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18228        }
18229
18230        if old_cursor_shape != self.cursor_shape {
18231            cx.emit(EditorEvent::CursorShapeChanged);
18232        }
18233
18234        let project_settings = ProjectSettings::get_global(cx);
18235        self.serialize_dirty_buffers =
18236            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18237
18238        if self.mode.is_full() {
18239            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18240            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18241            if self.show_inline_diagnostics != show_inline_diagnostics {
18242                self.show_inline_diagnostics = show_inline_diagnostics;
18243                self.refresh_inline_diagnostics(false, window, cx);
18244            }
18245
18246            if self.git_blame_inline_enabled != inline_blame_enabled {
18247                self.toggle_git_blame_inline_internal(false, window, cx);
18248            }
18249
18250            let minimap_settings = EditorSettings::get_global(cx).minimap;
18251            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18252                self.set_minimap_visibility(
18253                    self.minimap_visibility.toggle_visibility(),
18254                    window,
18255                    cx,
18256                );
18257            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18258                minimap_entity.update(cx, |minimap_editor, cx| {
18259                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18260                })
18261            }
18262        }
18263
18264        cx.notify();
18265    }
18266
18267    pub fn set_searchable(&mut self, searchable: bool) {
18268        self.searchable = searchable;
18269    }
18270
18271    pub fn searchable(&self) -> bool {
18272        self.searchable
18273    }
18274
18275    fn open_proposed_changes_editor(
18276        &mut self,
18277        _: &OpenProposedChangesEditor,
18278        window: &mut Window,
18279        cx: &mut Context<Self>,
18280    ) {
18281        let Some(workspace) = self.workspace() else {
18282            cx.propagate();
18283            return;
18284        };
18285
18286        let selections = self.selections.all::<usize>(cx);
18287        let multi_buffer = self.buffer.read(cx);
18288        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18289        let mut new_selections_by_buffer = HashMap::default();
18290        for selection in selections {
18291            for (buffer, range, _) in
18292                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18293            {
18294                let mut range = range.to_point(buffer);
18295                range.start.column = 0;
18296                range.end.column = buffer.line_len(range.end.row);
18297                new_selections_by_buffer
18298                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18299                    .or_insert(Vec::new())
18300                    .push(range)
18301            }
18302        }
18303
18304        let proposed_changes_buffers = new_selections_by_buffer
18305            .into_iter()
18306            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18307            .collect::<Vec<_>>();
18308        let proposed_changes_editor = cx.new(|cx| {
18309            ProposedChangesEditor::new(
18310                "Proposed changes",
18311                proposed_changes_buffers,
18312                self.project.clone(),
18313                window,
18314                cx,
18315            )
18316        });
18317
18318        window.defer(cx, move |window, cx| {
18319            workspace.update(cx, |workspace, cx| {
18320                workspace.active_pane().update(cx, |pane, cx| {
18321                    pane.add_item(
18322                        Box::new(proposed_changes_editor),
18323                        true,
18324                        true,
18325                        None,
18326                        window,
18327                        cx,
18328                    );
18329                });
18330            });
18331        });
18332    }
18333
18334    pub fn open_excerpts_in_split(
18335        &mut self,
18336        _: &OpenExcerptsSplit,
18337        window: &mut Window,
18338        cx: &mut Context<Self>,
18339    ) {
18340        self.open_excerpts_common(None, true, window, cx)
18341    }
18342
18343    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18344        self.open_excerpts_common(None, false, window, cx)
18345    }
18346
18347    fn open_excerpts_common(
18348        &mut self,
18349        jump_data: Option<JumpData>,
18350        split: bool,
18351        window: &mut Window,
18352        cx: &mut Context<Self>,
18353    ) {
18354        let Some(workspace) = self.workspace() else {
18355            cx.propagate();
18356            return;
18357        };
18358
18359        if self.buffer.read(cx).is_singleton() {
18360            cx.propagate();
18361            return;
18362        }
18363
18364        let mut new_selections_by_buffer = HashMap::default();
18365        match &jump_data {
18366            Some(JumpData::MultiBufferPoint {
18367                excerpt_id,
18368                position,
18369                anchor,
18370                line_offset_from_top,
18371            }) => {
18372                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18373                if let Some(buffer) = multi_buffer_snapshot
18374                    .buffer_id_for_excerpt(*excerpt_id)
18375                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18376                {
18377                    let buffer_snapshot = buffer.read(cx).snapshot();
18378                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18379                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18380                    } else {
18381                        buffer_snapshot.clip_point(*position, Bias::Left)
18382                    };
18383                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18384                    new_selections_by_buffer.insert(
18385                        buffer,
18386                        (
18387                            vec![jump_to_offset..jump_to_offset],
18388                            Some(*line_offset_from_top),
18389                        ),
18390                    );
18391                }
18392            }
18393            Some(JumpData::MultiBufferRow {
18394                row,
18395                line_offset_from_top,
18396            }) => {
18397                let point = MultiBufferPoint::new(row.0, 0);
18398                if let Some((buffer, buffer_point, _)) =
18399                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18400                {
18401                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18402                    new_selections_by_buffer
18403                        .entry(buffer)
18404                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18405                        .0
18406                        .push(buffer_offset..buffer_offset)
18407                }
18408            }
18409            None => {
18410                let selections = self.selections.all::<usize>(cx);
18411                let multi_buffer = self.buffer.read(cx);
18412                for selection in selections {
18413                    for (snapshot, range, _, anchor) in multi_buffer
18414                        .snapshot(cx)
18415                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18416                    {
18417                        if let Some(anchor) = anchor {
18418                            // selection is in a deleted hunk
18419                            let Some(buffer_id) = anchor.buffer_id else {
18420                                continue;
18421                            };
18422                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18423                                continue;
18424                            };
18425                            let offset = text::ToOffset::to_offset(
18426                                &anchor.text_anchor,
18427                                &buffer_handle.read(cx).snapshot(),
18428                            );
18429                            let range = offset..offset;
18430                            new_selections_by_buffer
18431                                .entry(buffer_handle)
18432                                .or_insert((Vec::new(), None))
18433                                .0
18434                                .push(range)
18435                        } else {
18436                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18437                            else {
18438                                continue;
18439                            };
18440                            new_selections_by_buffer
18441                                .entry(buffer_handle)
18442                                .or_insert((Vec::new(), None))
18443                                .0
18444                                .push(range)
18445                        }
18446                    }
18447                }
18448            }
18449        }
18450
18451        new_selections_by_buffer
18452            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18453
18454        if new_selections_by_buffer.is_empty() {
18455            return;
18456        }
18457
18458        // We defer the pane interaction because we ourselves are a workspace item
18459        // and activating a new item causes the pane to call a method on us reentrantly,
18460        // which panics if we're on the stack.
18461        window.defer(cx, move |window, cx| {
18462            workspace.update(cx, |workspace, cx| {
18463                let pane = if split {
18464                    workspace.adjacent_pane(window, cx)
18465                } else {
18466                    workspace.active_pane().clone()
18467                };
18468
18469                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18470                    let editor = buffer
18471                        .read(cx)
18472                        .file()
18473                        .is_none()
18474                        .then(|| {
18475                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18476                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18477                            // Instead, we try to activate the existing editor in the pane first.
18478                            let (editor, pane_item_index) =
18479                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18480                                    let editor = item.downcast::<Editor>()?;
18481                                    let singleton_buffer =
18482                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18483                                    if singleton_buffer == buffer {
18484                                        Some((editor, i))
18485                                    } else {
18486                                        None
18487                                    }
18488                                })?;
18489                            pane.update(cx, |pane, cx| {
18490                                pane.activate_item(pane_item_index, true, true, window, cx)
18491                            });
18492                            Some(editor)
18493                        })
18494                        .flatten()
18495                        .unwrap_or_else(|| {
18496                            workspace.open_project_item::<Self>(
18497                                pane.clone(),
18498                                buffer,
18499                                true,
18500                                true,
18501                                window,
18502                                cx,
18503                            )
18504                        });
18505
18506                    editor.update(cx, |editor, cx| {
18507                        let autoscroll = match scroll_offset {
18508                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18509                            None => Autoscroll::newest(),
18510                        };
18511                        let nav_history = editor.nav_history.take();
18512                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18513                            s.select_ranges(ranges);
18514                        });
18515                        editor.nav_history = nav_history;
18516                    });
18517                }
18518            })
18519        });
18520    }
18521
18522    // For now, don't allow opening excerpts in buffers that aren't backed by
18523    // regular project files.
18524    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18525        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18526    }
18527
18528    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18529        let snapshot = self.buffer.read(cx).read(cx);
18530        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18531        Some(
18532            ranges
18533                .iter()
18534                .map(move |range| {
18535                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18536                })
18537                .collect(),
18538        )
18539    }
18540
18541    fn selection_replacement_ranges(
18542        &self,
18543        range: Range<OffsetUtf16>,
18544        cx: &mut App,
18545    ) -> Vec<Range<OffsetUtf16>> {
18546        let selections = self.selections.all::<OffsetUtf16>(cx);
18547        let newest_selection = selections
18548            .iter()
18549            .max_by_key(|selection| selection.id)
18550            .unwrap();
18551        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18552        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18553        let snapshot = self.buffer.read(cx).read(cx);
18554        selections
18555            .into_iter()
18556            .map(|mut selection| {
18557                selection.start.0 =
18558                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18559                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18560                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18561                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18562            })
18563            .collect()
18564    }
18565
18566    fn report_editor_event(
18567        &self,
18568        event_type: &'static str,
18569        file_extension: Option<String>,
18570        cx: &App,
18571    ) {
18572        if cfg!(any(test, feature = "test-support")) {
18573            return;
18574        }
18575
18576        let Some(project) = &self.project else { return };
18577
18578        // If None, we are in a file without an extension
18579        let file = self
18580            .buffer
18581            .read(cx)
18582            .as_singleton()
18583            .and_then(|b| b.read(cx).file());
18584        let file_extension = file_extension.or(file
18585            .as_ref()
18586            .and_then(|file| Path::new(file.file_name(cx)).extension())
18587            .and_then(|e| e.to_str())
18588            .map(|a| a.to_string()));
18589
18590        let vim_mode = vim_enabled(cx);
18591
18592        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18593        let copilot_enabled = edit_predictions_provider
18594            == language::language_settings::EditPredictionProvider::Copilot;
18595        let copilot_enabled_for_language = self
18596            .buffer
18597            .read(cx)
18598            .language_settings(cx)
18599            .show_edit_predictions;
18600
18601        let project = project.read(cx);
18602        telemetry::event!(
18603            event_type,
18604            file_extension,
18605            vim_mode,
18606            copilot_enabled,
18607            copilot_enabled_for_language,
18608            edit_predictions_provider,
18609            is_via_ssh = project.is_via_ssh(),
18610        );
18611    }
18612
18613    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18614    /// with each line being an array of {text, highlight} objects.
18615    fn copy_highlight_json(
18616        &mut self,
18617        _: &CopyHighlightJson,
18618        window: &mut Window,
18619        cx: &mut Context<Self>,
18620    ) {
18621        #[derive(Serialize)]
18622        struct Chunk<'a> {
18623            text: String,
18624            highlight: Option<&'a str>,
18625        }
18626
18627        let snapshot = self.buffer.read(cx).snapshot(cx);
18628        let range = self
18629            .selected_text_range(false, window, cx)
18630            .and_then(|selection| {
18631                if selection.range.is_empty() {
18632                    None
18633                } else {
18634                    Some(selection.range)
18635                }
18636            })
18637            .unwrap_or_else(|| 0..snapshot.len());
18638
18639        let chunks = snapshot.chunks(range, true);
18640        let mut lines = Vec::new();
18641        let mut line: VecDeque<Chunk> = VecDeque::new();
18642
18643        let Some(style) = self.style.as_ref() else {
18644            return;
18645        };
18646
18647        for chunk in chunks {
18648            let highlight = chunk
18649                .syntax_highlight_id
18650                .and_then(|id| id.name(&style.syntax));
18651            let mut chunk_lines = chunk.text.split('\n').peekable();
18652            while let Some(text) = chunk_lines.next() {
18653                let mut merged_with_last_token = false;
18654                if let Some(last_token) = line.back_mut() {
18655                    if last_token.highlight == highlight {
18656                        last_token.text.push_str(text);
18657                        merged_with_last_token = true;
18658                    }
18659                }
18660
18661                if !merged_with_last_token {
18662                    line.push_back(Chunk {
18663                        text: text.into(),
18664                        highlight,
18665                    });
18666                }
18667
18668                if chunk_lines.peek().is_some() {
18669                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18670                        line.pop_front();
18671                    }
18672                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18673                        line.pop_back();
18674                    }
18675
18676                    lines.push(mem::take(&mut line));
18677                }
18678            }
18679        }
18680
18681        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18682            return;
18683        };
18684        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18685    }
18686
18687    pub fn open_context_menu(
18688        &mut self,
18689        _: &OpenContextMenu,
18690        window: &mut Window,
18691        cx: &mut Context<Self>,
18692    ) {
18693        self.request_autoscroll(Autoscroll::newest(), cx);
18694        let position = self.selections.newest_display(cx).start;
18695        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18696    }
18697
18698    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18699        &self.inlay_hint_cache
18700    }
18701
18702    pub fn replay_insert_event(
18703        &mut self,
18704        text: &str,
18705        relative_utf16_range: Option<Range<isize>>,
18706        window: &mut Window,
18707        cx: &mut Context<Self>,
18708    ) {
18709        if !self.input_enabled {
18710            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18711            return;
18712        }
18713        if let Some(relative_utf16_range) = relative_utf16_range {
18714            let selections = self.selections.all::<OffsetUtf16>(cx);
18715            self.change_selections(None, window, cx, |s| {
18716                let new_ranges = selections.into_iter().map(|range| {
18717                    let start = OffsetUtf16(
18718                        range
18719                            .head()
18720                            .0
18721                            .saturating_add_signed(relative_utf16_range.start),
18722                    );
18723                    let end = OffsetUtf16(
18724                        range
18725                            .head()
18726                            .0
18727                            .saturating_add_signed(relative_utf16_range.end),
18728                    );
18729                    start..end
18730                });
18731                s.select_ranges(new_ranges);
18732            });
18733        }
18734
18735        self.handle_input(text, window, cx);
18736    }
18737
18738    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18739        let Some(provider) = self.semantics_provider.as_ref() else {
18740            return false;
18741        };
18742
18743        let mut supports = false;
18744        self.buffer().update(cx, |this, cx| {
18745            this.for_each_buffer(|buffer| {
18746                supports |= provider.supports_inlay_hints(buffer, cx);
18747            });
18748        });
18749
18750        supports
18751    }
18752
18753    pub fn is_focused(&self, window: &Window) -> bool {
18754        self.focus_handle.is_focused(window)
18755    }
18756
18757    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18758        cx.emit(EditorEvent::Focused);
18759
18760        if let Some(descendant) = self
18761            .last_focused_descendant
18762            .take()
18763            .and_then(|descendant| descendant.upgrade())
18764        {
18765            window.focus(&descendant);
18766        } else {
18767            if let Some(blame) = self.blame.as_ref() {
18768                blame.update(cx, GitBlame::focus)
18769            }
18770
18771            self.blink_manager.update(cx, BlinkManager::enable);
18772            self.show_cursor_names(window, cx);
18773            self.buffer.update(cx, |buffer, cx| {
18774                buffer.finalize_last_transaction(cx);
18775                if self.leader_id.is_none() {
18776                    buffer.set_active_selections(
18777                        &self.selections.disjoint_anchors(),
18778                        self.selections.line_mode,
18779                        self.cursor_shape,
18780                        cx,
18781                    );
18782                }
18783            });
18784        }
18785    }
18786
18787    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18788        cx.emit(EditorEvent::FocusedIn)
18789    }
18790
18791    fn handle_focus_out(
18792        &mut self,
18793        event: FocusOutEvent,
18794        _window: &mut Window,
18795        cx: &mut Context<Self>,
18796    ) {
18797        if event.blurred != self.focus_handle {
18798            self.last_focused_descendant = Some(event.blurred);
18799        }
18800        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18801    }
18802
18803    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18804        self.blink_manager.update(cx, BlinkManager::disable);
18805        self.buffer
18806            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18807
18808        if let Some(blame) = self.blame.as_ref() {
18809            blame.update(cx, GitBlame::blur)
18810        }
18811        if !self.hover_state.focused(window, cx) {
18812            hide_hover(self, cx);
18813        }
18814        if !self
18815            .context_menu
18816            .borrow()
18817            .as_ref()
18818            .is_some_and(|context_menu| context_menu.focused(window, cx))
18819        {
18820            self.hide_context_menu(window, cx);
18821        }
18822        self.discard_inline_completion(false, cx);
18823        cx.emit(EditorEvent::Blurred);
18824        cx.notify();
18825    }
18826
18827    pub fn register_action<A: Action>(
18828        &mut self,
18829        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18830    ) -> Subscription {
18831        let id = self.next_editor_action_id.post_inc();
18832        let listener = Arc::new(listener);
18833        self.editor_actions.borrow_mut().insert(
18834            id,
18835            Box::new(move |window, _| {
18836                let listener = listener.clone();
18837                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18838                    let action = action.downcast_ref().unwrap();
18839                    if phase == DispatchPhase::Bubble {
18840                        listener(action, window, cx)
18841                    }
18842                })
18843            }),
18844        );
18845
18846        let editor_actions = self.editor_actions.clone();
18847        Subscription::new(move || {
18848            editor_actions.borrow_mut().remove(&id);
18849        })
18850    }
18851
18852    pub fn file_header_size(&self) -> u32 {
18853        FILE_HEADER_HEIGHT
18854    }
18855
18856    pub fn restore(
18857        &mut self,
18858        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
18859        window: &mut Window,
18860        cx: &mut Context<Self>,
18861    ) {
18862        let workspace = self.workspace();
18863        let project = self.project.as_ref();
18864        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
18865            let mut tasks = Vec::new();
18866            for (buffer_id, changes) in revert_changes {
18867                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
18868                    buffer.update(cx, |buffer, cx| {
18869                        buffer.edit(
18870                            changes
18871                                .into_iter()
18872                                .map(|(range, text)| (range, text.to_string())),
18873                            None,
18874                            cx,
18875                        );
18876                    });
18877
18878                    if let Some(project) =
18879                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
18880                    {
18881                        project.update(cx, |project, cx| {
18882                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
18883                        })
18884                    }
18885                }
18886            }
18887            tasks
18888        });
18889        cx.spawn_in(window, async move |_, cx| {
18890            for (buffer, task) in save_tasks {
18891                let result = task.await;
18892                if result.is_err() {
18893                    let Some(path) = buffer
18894                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
18895                        .ok()
18896                    else {
18897                        continue;
18898                    };
18899                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
18900                        let Some(task) = cx
18901                            .update_window_entity(&workspace, |workspace, window, cx| {
18902                                workspace
18903                                    .open_path_preview(path, None, false, false, false, window, cx)
18904                            })
18905                            .ok()
18906                        else {
18907                            continue;
18908                        };
18909                        task.await.log_err();
18910                    }
18911                }
18912            }
18913        })
18914        .detach();
18915        self.change_selections(None, window, cx, |selections| selections.refresh());
18916    }
18917
18918    pub fn to_pixel_point(
18919        &self,
18920        source: multi_buffer::Anchor,
18921        editor_snapshot: &EditorSnapshot,
18922        window: &mut Window,
18923    ) -> Option<gpui::Point<Pixels>> {
18924        let source_point = source.to_display_point(editor_snapshot);
18925        self.display_to_pixel_point(source_point, editor_snapshot, window)
18926    }
18927
18928    pub fn display_to_pixel_point(
18929        &self,
18930        source: DisplayPoint,
18931        editor_snapshot: &EditorSnapshot,
18932        window: &mut Window,
18933    ) -> Option<gpui::Point<Pixels>> {
18934        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
18935        let text_layout_details = self.text_layout_details(window);
18936        let scroll_top = text_layout_details
18937            .scroll_anchor
18938            .scroll_position(editor_snapshot)
18939            .y;
18940
18941        if source.row().as_f32() < scroll_top.floor() {
18942            return None;
18943        }
18944        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
18945        let source_y = line_height * (source.row().as_f32() - scroll_top);
18946        Some(gpui::Point::new(source_x, source_y))
18947    }
18948
18949    pub fn has_visible_completions_menu(&self) -> bool {
18950        !self.edit_prediction_preview_is_active()
18951            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
18952                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
18953            })
18954    }
18955
18956    pub fn register_addon<T: Addon>(&mut self, instance: T) {
18957        if self.mode.is_minimap() {
18958            return;
18959        }
18960        self.addons
18961            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
18962    }
18963
18964    pub fn unregister_addon<T: Addon>(&mut self) {
18965        self.addons.remove(&std::any::TypeId::of::<T>());
18966    }
18967
18968    pub fn addon<T: Addon>(&self) -> Option<&T> {
18969        let type_id = std::any::TypeId::of::<T>();
18970        self.addons
18971            .get(&type_id)
18972            .and_then(|item| item.to_any().downcast_ref::<T>())
18973    }
18974
18975    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
18976        let type_id = std::any::TypeId::of::<T>();
18977        self.addons
18978            .get_mut(&type_id)
18979            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
18980    }
18981
18982    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
18983        let text_layout_details = self.text_layout_details(window);
18984        let style = &text_layout_details.editor_style;
18985        let font_id = window.text_system().resolve_font(&style.text.font());
18986        let font_size = style.text.font_size.to_pixels(window.rem_size());
18987        let line_height = style.text.line_height_in_pixels(window.rem_size());
18988        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
18989
18990        gpui::Size::new(em_width, line_height)
18991    }
18992
18993    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
18994        self.load_diff_task.clone()
18995    }
18996
18997    fn read_metadata_from_db(
18998        &mut self,
18999        item_id: u64,
19000        workspace_id: WorkspaceId,
19001        window: &mut Window,
19002        cx: &mut Context<Editor>,
19003    ) {
19004        if self.is_singleton(cx)
19005            && !self.mode.is_minimap()
19006            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19007        {
19008            let buffer_snapshot = OnceCell::new();
19009
19010            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19011                if !folds.is_empty() {
19012                    let snapshot =
19013                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19014                    self.fold_ranges(
19015                        folds
19016                            .into_iter()
19017                            .map(|(start, end)| {
19018                                snapshot.clip_offset(start, Bias::Left)
19019                                    ..snapshot.clip_offset(end, Bias::Right)
19020                            })
19021                            .collect(),
19022                        false,
19023                        window,
19024                        cx,
19025                    );
19026                }
19027            }
19028
19029            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19030                if !selections.is_empty() {
19031                    let snapshot =
19032                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19033                    self.change_selections(None, window, cx, |s| {
19034                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19035                            snapshot.clip_offset(start, Bias::Left)
19036                                ..snapshot.clip_offset(end, Bias::Right)
19037                        }));
19038                    });
19039                }
19040            };
19041        }
19042
19043        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19044    }
19045}
19046
19047fn vim_enabled(cx: &App) -> bool {
19048    cx.global::<SettingsStore>()
19049        .raw_user_settings()
19050        .get("vim_mode")
19051        == Some(&serde_json::Value::Bool(true))
19052}
19053
19054// Consider user intent and default settings
19055fn choose_completion_range(
19056    completion: &Completion,
19057    intent: CompletionIntent,
19058    buffer: &Entity<Buffer>,
19059    cx: &mut Context<Editor>,
19060) -> Range<usize> {
19061    fn should_replace(
19062        completion: &Completion,
19063        insert_range: &Range<text::Anchor>,
19064        intent: CompletionIntent,
19065        completion_mode_setting: LspInsertMode,
19066        buffer: &Buffer,
19067    ) -> bool {
19068        // specific actions take precedence over settings
19069        match intent {
19070            CompletionIntent::CompleteWithInsert => return false,
19071            CompletionIntent::CompleteWithReplace => return true,
19072            CompletionIntent::Complete | CompletionIntent::Compose => {}
19073        }
19074
19075        match completion_mode_setting {
19076            LspInsertMode::Insert => false,
19077            LspInsertMode::Replace => true,
19078            LspInsertMode::ReplaceSubsequence => {
19079                let mut text_to_replace = buffer.chars_for_range(
19080                    buffer.anchor_before(completion.replace_range.start)
19081                        ..buffer.anchor_after(completion.replace_range.end),
19082                );
19083                let mut completion_text = completion.new_text.chars();
19084
19085                // is `text_to_replace` a subsequence of `completion_text`
19086                text_to_replace
19087                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19088            }
19089            LspInsertMode::ReplaceSuffix => {
19090                let range_after_cursor = insert_range.end..completion.replace_range.end;
19091
19092                let text_after_cursor = buffer
19093                    .text_for_range(
19094                        buffer.anchor_before(range_after_cursor.start)
19095                            ..buffer.anchor_after(range_after_cursor.end),
19096                    )
19097                    .collect::<String>();
19098                completion.new_text.ends_with(&text_after_cursor)
19099            }
19100        }
19101    }
19102
19103    let buffer = buffer.read(cx);
19104
19105    if let CompletionSource::Lsp {
19106        insert_range: Some(insert_range),
19107        ..
19108    } = &completion.source
19109    {
19110        let completion_mode_setting =
19111            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19112                .completions
19113                .lsp_insert_mode;
19114
19115        if !should_replace(
19116            completion,
19117            &insert_range,
19118            intent,
19119            completion_mode_setting,
19120            buffer,
19121        ) {
19122            return insert_range.to_offset(buffer);
19123        }
19124    }
19125
19126    completion.replace_range.to_offset(buffer)
19127}
19128
19129fn insert_extra_newline_brackets(
19130    buffer: &MultiBufferSnapshot,
19131    range: Range<usize>,
19132    language: &language::LanguageScope,
19133) -> bool {
19134    let leading_whitespace_len = buffer
19135        .reversed_chars_at(range.start)
19136        .take_while(|c| c.is_whitespace() && *c != '\n')
19137        .map(|c| c.len_utf8())
19138        .sum::<usize>();
19139    let trailing_whitespace_len = buffer
19140        .chars_at(range.end)
19141        .take_while(|c| c.is_whitespace() && *c != '\n')
19142        .map(|c| c.len_utf8())
19143        .sum::<usize>();
19144    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19145
19146    language.brackets().any(|(pair, enabled)| {
19147        let pair_start = pair.start.trim_end();
19148        let pair_end = pair.end.trim_start();
19149
19150        enabled
19151            && pair.newline
19152            && buffer.contains_str_at(range.end, pair_end)
19153            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19154    })
19155}
19156
19157fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19158    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19159        [(buffer, range, _)] => (*buffer, range.clone()),
19160        _ => return false,
19161    };
19162    let pair = {
19163        let mut result: Option<BracketMatch> = None;
19164
19165        for pair in buffer
19166            .all_bracket_ranges(range.clone())
19167            .filter(move |pair| {
19168                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19169            })
19170        {
19171            let len = pair.close_range.end - pair.open_range.start;
19172
19173            if let Some(existing) = &result {
19174                let existing_len = existing.close_range.end - existing.open_range.start;
19175                if len > existing_len {
19176                    continue;
19177                }
19178            }
19179
19180            result = Some(pair);
19181        }
19182
19183        result
19184    };
19185    let Some(pair) = pair else {
19186        return false;
19187    };
19188    pair.newline_only
19189        && buffer
19190            .chars_for_range(pair.open_range.end..range.start)
19191            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19192            .all(|c| c.is_whitespace() && c != '\n')
19193}
19194
19195fn update_uncommitted_diff_for_buffer(
19196    editor: Entity<Editor>,
19197    project: &Entity<Project>,
19198    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19199    buffer: Entity<MultiBuffer>,
19200    cx: &mut App,
19201) -> Task<()> {
19202    let mut tasks = Vec::new();
19203    project.update(cx, |project, cx| {
19204        for buffer in buffers {
19205            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19206                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19207            }
19208        }
19209    });
19210    cx.spawn(async move |cx| {
19211        let diffs = future::join_all(tasks).await;
19212        if editor
19213            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19214            .unwrap_or(false)
19215        {
19216            return;
19217        }
19218
19219        buffer
19220            .update(cx, |buffer, cx| {
19221                for diff in diffs.into_iter().flatten() {
19222                    buffer.add_diff(diff, cx);
19223                }
19224            })
19225            .ok();
19226    })
19227}
19228
19229fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19230    let tab_size = tab_size.get() as usize;
19231    let mut width = offset;
19232
19233    for ch in text.chars() {
19234        width += if ch == '\t' {
19235            tab_size - (width % tab_size)
19236        } else {
19237            1
19238        };
19239    }
19240
19241    width - offset
19242}
19243
19244#[cfg(test)]
19245mod tests {
19246    use super::*;
19247
19248    #[test]
19249    fn test_string_size_with_expanded_tabs() {
19250        let nz = |val| NonZeroU32::new(val).unwrap();
19251        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19252        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19253        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19254        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19255        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19256        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19257        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19258        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19259    }
19260}
19261
19262/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19263struct WordBreakingTokenizer<'a> {
19264    input: &'a str,
19265}
19266
19267impl<'a> WordBreakingTokenizer<'a> {
19268    fn new(input: &'a str) -> Self {
19269        Self { input }
19270    }
19271}
19272
19273fn is_char_ideographic(ch: char) -> bool {
19274    use unicode_script::Script::*;
19275    use unicode_script::UnicodeScript;
19276    matches!(ch.script(), Han | Tangut | Yi)
19277}
19278
19279fn is_grapheme_ideographic(text: &str) -> bool {
19280    text.chars().any(is_char_ideographic)
19281}
19282
19283fn is_grapheme_whitespace(text: &str) -> bool {
19284    text.chars().any(|x| x.is_whitespace())
19285}
19286
19287fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19288    text.chars().next().map_or(false, |ch| {
19289        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19290    })
19291}
19292
19293#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19294enum WordBreakToken<'a> {
19295    Word { token: &'a str, grapheme_len: usize },
19296    InlineWhitespace { token: &'a str, grapheme_len: usize },
19297    Newline,
19298}
19299
19300impl<'a> Iterator for WordBreakingTokenizer<'a> {
19301    /// Yields a span, the count of graphemes in the token, and whether it was
19302    /// whitespace. Note that it also breaks at word boundaries.
19303    type Item = WordBreakToken<'a>;
19304
19305    fn next(&mut self) -> Option<Self::Item> {
19306        use unicode_segmentation::UnicodeSegmentation;
19307        if self.input.is_empty() {
19308            return None;
19309        }
19310
19311        let mut iter = self.input.graphemes(true).peekable();
19312        let mut offset = 0;
19313        let mut grapheme_len = 0;
19314        if let Some(first_grapheme) = iter.next() {
19315            let is_newline = first_grapheme == "\n";
19316            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19317            offset += first_grapheme.len();
19318            grapheme_len += 1;
19319            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19320                if let Some(grapheme) = iter.peek().copied() {
19321                    if should_stay_with_preceding_ideograph(grapheme) {
19322                        offset += grapheme.len();
19323                        grapheme_len += 1;
19324                    }
19325                }
19326            } else {
19327                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19328                let mut next_word_bound = words.peek().copied();
19329                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19330                    next_word_bound = words.next();
19331                }
19332                while let Some(grapheme) = iter.peek().copied() {
19333                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19334                        break;
19335                    };
19336                    if is_grapheme_whitespace(grapheme) != is_whitespace
19337                        || (grapheme == "\n") != is_newline
19338                    {
19339                        break;
19340                    };
19341                    offset += grapheme.len();
19342                    grapheme_len += 1;
19343                    iter.next();
19344                }
19345            }
19346            let token = &self.input[..offset];
19347            self.input = &self.input[offset..];
19348            if token == "\n" {
19349                Some(WordBreakToken::Newline)
19350            } else if is_whitespace {
19351                Some(WordBreakToken::InlineWhitespace {
19352                    token,
19353                    grapheme_len,
19354                })
19355            } else {
19356                Some(WordBreakToken::Word {
19357                    token,
19358                    grapheme_len,
19359                })
19360            }
19361        } else {
19362            None
19363        }
19364    }
19365}
19366
19367#[test]
19368fn test_word_breaking_tokenizer() {
19369    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19370        ("", &[]),
19371        ("  ", &[whitespace("  ", 2)]),
19372        ("Ʒ", &[word("Ʒ", 1)]),
19373        ("Ǽ", &[word("Ǽ", 1)]),
19374        ("", &[word("", 1)]),
19375        ("⋑⋑", &[word("⋑⋑", 2)]),
19376        (
19377            "原理,进而",
19378            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19379        ),
19380        (
19381            "hello world",
19382            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19383        ),
19384        (
19385            "hello, world",
19386            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19387        ),
19388        (
19389            "  hello world",
19390            &[
19391                whitespace("  ", 2),
19392                word("hello", 5),
19393                whitespace(" ", 1),
19394                word("world", 5),
19395            ],
19396        ),
19397        (
19398            "这是什么 \n 钢笔",
19399            &[
19400                word("", 1),
19401                word("", 1),
19402                word("", 1),
19403                word("", 1),
19404                whitespace(" ", 1),
19405                newline(),
19406                whitespace(" ", 1),
19407                word("", 1),
19408                word("", 1),
19409            ],
19410        ),
19411        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19412    ];
19413
19414    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19415        WordBreakToken::Word {
19416            token,
19417            grapheme_len,
19418        }
19419    }
19420
19421    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19422        WordBreakToken::InlineWhitespace {
19423            token,
19424            grapheme_len,
19425        }
19426    }
19427
19428    fn newline() -> WordBreakToken<'static> {
19429        WordBreakToken::Newline
19430    }
19431
19432    for (input, result) in tests {
19433        assert_eq!(
19434            WordBreakingTokenizer::new(input)
19435                .collect::<Vec<_>>()
19436                .as_slice(),
19437            *result,
19438        );
19439    }
19440}
19441
19442fn wrap_with_prefix(
19443    line_prefix: String,
19444    unwrapped_text: String,
19445    wrap_column: usize,
19446    tab_size: NonZeroU32,
19447    preserve_existing_whitespace: bool,
19448) -> String {
19449    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19450    let mut wrapped_text = String::new();
19451    let mut current_line = line_prefix.clone();
19452
19453    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19454    let mut current_line_len = line_prefix_len;
19455    let mut in_whitespace = false;
19456    for token in tokenizer {
19457        let have_preceding_whitespace = in_whitespace;
19458        match token {
19459            WordBreakToken::Word {
19460                token,
19461                grapheme_len,
19462            } => {
19463                in_whitespace = false;
19464                if current_line_len + grapheme_len > wrap_column
19465                    && current_line_len != line_prefix_len
19466                {
19467                    wrapped_text.push_str(current_line.trim_end());
19468                    wrapped_text.push('\n');
19469                    current_line.truncate(line_prefix.len());
19470                    current_line_len = line_prefix_len;
19471                }
19472                current_line.push_str(token);
19473                current_line_len += grapheme_len;
19474            }
19475            WordBreakToken::InlineWhitespace {
19476                mut token,
19477                mut grapheme_len,
19478            } => {
19479                in_whitespace = true;
19480                if have_preceding_whitespace && !preserve_existing_whitespace {
19481                    continue;
19482                }
19483                if !preserve_existing_whitespace {
19484                    token = " ";
19485                    grapheme_len = 1;
19486                }
19487                if current_line_len + grapheme_len > wrap_column {
19488                    wrapped_text.push_str(current_line.trim_end());
19489                    wrapped_text.push('\n');
19490                    current_line.truncate(line_prefix.len());
19491                    current_line_len = line_prefix_len;
19492                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19493                    current_line.push_str(token);
19494                    current_line_len += grapheme_len;
19495                }
19496            }
19497            WordBreakToken::Newline => {
19498                in_whitespace = true;
19499                if preserve_existing_whitespace {
19500                    wrapped_text.push_str(current_line.trim_end());
19501                    wrapped_text.push('\n');
19502                    current_line.truncate(line_prefix.len());
19503                    current_line_len = line_prefix_len;
19504                } else if have_preceding_whitespace {
19505                    continue;
19506                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19507                {
19508                    wrapped_text.push_str(current_line.trim_end());
19509                    wrapped_text.push('\n');
19510                    current_line.truncate(line_prefix.len());
19511                    current_line_len = line_prefix_len;
19512                } else if current_line_len != line_prefix_len {
19513                    current_line.push(' ');
19514                    current_line_len += 1;
19515                }
19516            }
19517        }
19518    }
19519
19520    if !current_line.is_empty() {
19521        wrapped_text.push_str(&current_line);
19522    }
19523    wrapped_text
19524}
19525
19526#[test]
19527fn test_wrap_with_prefix() {
19528    assert_eq!(
19529        wrap_with_prefix(
19530            "# ".to_string(),
19531            "abcdefg".to_string(),
19532            4,
19533            NonZeroU32::new(4).unwrap(),
19534            false,
19535        ),
19536        "# abcdefg"
19537    );
19538    assert_eq!(
19539        wrap_with_prefix(
19540            "".to_string(),
19541            "\thello world".to_string(),
19542            8,
19543            NonZeroU32::new(4).unwrap(),
19544            false,
19545        ),
19546        "hello\nworld"
19547    );
19548    assert_eq!(
19549        wrap_with_prefix(
19550            "// ".to_string(),
19551            "xx \nyy zz aa bb cc".to_string(),
19552            12,
19553            NonZeroU32::new(4).unwrap(),
19554            false,
19555        ),
19556        "// xx yy zz\n// aa bb cc"
19557    );
19558    assert_eq!(
19559        wrap_with_prefix(
19560            String::new(),
19561            "这是什么 \n 钢笔".to_string(),
19562            3,
19563            NonZeroU32::new(4).unwrap(),
19564            false,
19565        ),
19566        "这是什\n么 钢\n"
19567    );
19568}
19569
19570pub trait CollaborationHub {
19571    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19572    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19573    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19574}
19575
19576impl CollaborationHub for Entity<Project> {
19577    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19578        self.read(cx).collaborators()
19579    }
19580
19581    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19582        self.read(cx).user_store().read(cx).participant_indices()
19583    }
19584
19585    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19586        let this = self.read(cx);
19587        let user_ids = this.collaborators().values().map(|c| c.user_id);
19588        this.user_store().read_with(cx, |user_store, cx| {
19589            user_store.participant_names(user_ids, cx)
19590        })
19591    }
19592}
19593
19594pub trait SemanticsProvider {
19595    fn hover(
19596        &self,
19597        buffer: &Entity<Buffer>,
19598        position: text::Anchor,
19599        cx: &mut App,
19600    ) -> Option<Task<Vec<project::Hover>>>;
19601
19602    fn inline_values(
19603        &self,
19604        buffer_handle: Entity<Buffer>,
19605        range: Range<text::Anchor>,
19606        cx: &mut App,
19607    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19608
19609    fn inlay_hints(
19610        &self,
19611        buffer_handle: Entity<Buffer>,
19612        range: Range<text::Anchor>,
19613        cx: &mut App,
19614    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19615
19616    fn resolve_inlay_hint(
19617        &self,
19618        hint: InlayHint,
19619        buffer_handle: Entity<Buffer>,
19620        server_id: LanguageServerId,
19621        cx: &mut App,
19622    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19623
19624    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19625
19626    fn document_highlights(
19627        &self,
19628        buffer: &Entity<Buffer>,
19629        position: text::Anchor,
19630        cx: &mut App,
19631    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19632
19633    fn definitions(
19634        &self,
19635        buffer: &Entity<Buffer>,
19636        position: text::Anchor,
19637        kind: GotoDefinitionKind,
19638        cx: &mut App,
19639    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19640
19641    fn range_for_rename(
19642        &self,
19643        buffer: &Entity<Buffer>,
19644        position: text::Anchor,
19645        cx: &mut App,
19646    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19647
19648    fn perform_rename(
19649        &self,
19650        buffer: &Entity<Buffer>,
19651        position: text::Anchor,
19652        new_name: String,
19653        cx: &mut App,
19654    ) -> Option<Task<Result<ProjectTransaction>>>;
19655}
19656
19657pub trait CompletionProvider {
19658    fn completions(
19659        &self,
19660        excerpt_id: ExcerptId,
19661        buffer: &Entity<Buffer>,
19662        buffer_position: text::Anchor,
19663        trigger: CompletionContext,
19664        window: &mut Window,
19665        cx: &mut Context<Editor>,
19666    ) -> Task<Result<Option<Vec<Completion>>>>;
19667
19668    fn resolve_completions(
19669        &self,
19670        buffer: Entity<Buffer>,
19671        completion_indices: Vec<usize>,
19672        completions: Rc<RefCell<Box<[Completion]>>>,
19673        cx: &mut Context<Editor>,
19674    ) -> Task<Result<bool>>;
19675
19676    fn apply_additional_edits_for_completion(
19677        &self,
19678        _buffer: Entity<Buffer>,
19679        _completions: Rc<RefCell<Box<[Completion]>>>,
19680        _completion_index: usize,
19681        _push_to_history: bool,
19682        _cx: &mut Context<Editor>,
19683    ) -> Task<Result<Option<language::Transaction>>> {
19684        Task::ready(Ok(None))
19685    }
19686
19687    fn is_completion_trigger(
19688        &self,
19689        buffer: &Entity<Buffer>,
19690        position: language::Anchor,
19691        text: &str,
19692        trigger_in_words: bool,
19693        cx: &mut Context<Editor>,
19694    ) -> bool;
19695
19696    fn sort_completions(&self) -> bool {
19697        true
19698    }
19699
19700    fn filter_completions(&self) -> bool {
19701        true
19702    }
19703}
19704
19705pub trait CodeActionProvider {
19706    fn id(&self) -> Arc<str>;
19707
19708    fn code_actions(
19709        &self,
19710        buffer: &Entity<Buffer>,
19711        range: Range<text::Anchor>,
19712        window: &mut Window,
19713        cx: &mut App,
19714    ) -> Task<Result<Vec<CodeAction>>>;
19715
19716    fn apply_code_action(
19717        &self,
19718        buffer_handle: Entity<Buffer>,
19719        action: CodeAction,
19720        excerpt_id: ExcerptId,
19721        push_to_history: bool,
19722        window: &mut Window,
19723        cx: &mut App,
19724    ) -> Task<Result<ProjectTransaction>>;
19725}
19726
19727impl CodeActionProvider for Entity<Project> {
19728    fn id(&self) -> Arc<str> {
19729        "project".into()
19730    }
19731
19732    fn code_actions(
19733        &self,
19734        buffer: &Entity<Buffer>,
19735        range: Range<text::Anchor>,
19736        _window: &mut Window,
19737        cx: &mut App,
19738    ) -> Task<Result<Vec<CodeAction>>> {
19739        self.update(cx, |project, cx| {
19740            let code_lens = project.code_lens(buffer, range.clone(), cx);
19741            let code_actions = project.code_actions(buffer, range, None, cx);
19742            cx.background_spawn(async move {
19743                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19744                Ok(code_lens
19745                    .context("code lens fetch")?
19746                    .into_iter()
19747                    .chain(code_actions.context("code action fetch")?)
19748                    .collect())
19749            })
19750        })
19751    }
19752
19753    fn apply_code_action(
19754        &self,
19755        buffer_handle: Entity<Buffer>,
19756        action: CodeAction,
19757        _excerpt_id: ExcerptId,
19758        push_to_history: bool,
19759        _window: &mut Window,
19760        cx: &mut App,
19761    ) -> Task<Result<ProjectTransaction>> {
19762        self.update(cx, |project, cx| {
19763            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19764        })
19765    }
19766}
19767
19768fn snippet_completions(
19769    project: &Project,
19770    buffer: &Entity<Buffer>,
19771    buffer_position: text::Anchor,
19772    cx: &mut App,
19773) -> Task<Result<Vec<Completion>>> {
19774    let languages = buffer.read(cx).languages_at(buffer_position);
19775    let snippet_store = project.snippets().read(cx);
19776
19777    let scopes: Vec<_> = languages
19778        .iter()
19779        .filter_map(|language| {
19780            let language_name = language.lsp_id();
19781            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19782
19783            if snippets.is_empty() {
19784                None
19785            } else {
19786                Some((language.default_scope(), snippets))
19787            }
19788        })
19789        .collect();
19790
19791    if scopes.is_empty() {
19792        return Task::ready(Ok(vec![]));
19793    }
19794
19795    let snapshot = buffer.read(cx).text_snapshot();
19796    let chars: String = snapshot
19797        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19798        .collect();
19799    let executor = cx.background_executor().clone();
19800
19801    cx.background_spawn(async move {
19802        let mut all_results: Vec<Completion> = Vec::new();
19803        for (scope, snippets) in scopes.into_iter() {
19804            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19805            let mut last_word = chars
19806                .chars()
19807                .take_while(|c| classifier.is_word(*c))
19808                .collect::<String>();
19809            last_word = last_word.chars().rev().collect();
19810
19811            if last_word.is_empty() {
19812                return Ok(vec![]);
19813            }
19814
19815            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19816            let to_lsp = |point: &text::Anchor| {
19817                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19818                point_to_lsp(end)
19819            };
19820            let lsp_end = to_lsp(&buffer_position);
19821
19822            let candidates = snippets
19823                .iter()
19824                .enumerate()
19825                .flat_map(|(ix, snippet)| {
19826                    snippet
19827                        .prefix
19828                        .iter()
19829                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19830                })
19831                .collect::<Vec<StringMatchCandidate>>();
19832
19833            let mut matches = fuzzy::match_strings(
19834                &candidates,
19835                &last_word,
19836                last_word.chars().any(|c| c.is_uppercase()),
19837                100,
19838                &Default::default(),
19839                executor.clone(),
19840            )
19841            .await;
19842
19843            // Remove all candidates where the query's start does not match the start of any word in the candidate
19844            if let Some(query_start) = last_word.chars().next() {
19845                matches.retain(|string_match| {
19846                    split_words(&string_match.string).any(|word| {
19847                        // Check that the first codepoint of the word as lowercase matches the first
19848                        // codepoint of the query as lowercase
19849                        word.chars()
19850                            .flat_map(|codepoint| codepoint.to_lowercase())
19851                            .zip(query_start.to_lowercase())
19852                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19853                    })
19854                });
19855            }
19856
19857            let matched_strings = matches
19858                .into_iter()
19859                .map(|m| m.string)
19860                .collect::<HashSet<_>>();
19861
19862            let mut result: Vec<Completion> = snippets
19863                .iter()
19864                .filter_map(|snippet| {
19865                    let matching_prefix = snippet
19866                        .prefix
19867                        .iter()
19868                        .find(|prefix| matched_strings.contains(*prefix))?;
19869                    let start = as_offset - last_word.len();
19870                    let start = snapshot.anchor_before(start);
19871                    let range = start..buffer_position;
19872                    let lsp_start = to_lsp(&start);
19873                    let lsp_range = lsp::Range {
19874                        start: lsp_start,
19875                        end: lsp_end,
19876                    };
19877                    Some(Completion {
19878                        replace_range: range,
19879                        new_text: snippet.body.clone(),
19880                        source: CompletionSource::Lsp {
19881                            insert_range: None,
19882                            server_id: LanguageServerId(usize::MAX),
19883                            resolved: true,
19884                            lsp_completion: Box::new(lsp::CompletionItem {
19885                                label: snippet.prefix.first().unwrap().clone(),
19886                                kind: Some(CompletionItemKind::SNIPPET),
19887                                label_details: snippet.description.as_ref().map(|description| {
19888                                    lsp::CompletionItemLabelDetails {
19889                                        detail: Some(description.clone()),
19890                                        description: None,
19891                                    }
19892                                }),
19893                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19894                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19895                                    lsp::InsertReplaceEdit {
19896                                        new_text: snippet.body.clone(),
19897                                        insert: lsp_range,
19898                                        replace: lsp_range,
19899                                    },
19900                                )),
19901                                filter_text: Some(snippet.body.clone()),
19902                                sort_text: Some(char::MAX.to_string()),
19903                                ..lsp::CompletionItem::default()
19904                            }),
19905                            lsp_defaults: None,
19906                        },
19907                        label: CodeLabel {
19908                            text: matching_prefix.clone(),
19909                            runs: Vec::new(),
19910                            filter_range: 0..matching_prefix.len(),
19911                        },
19912                        icon_path: None,
19913                        documentation: Some(
19914                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
19915                                single_line: snippet.name.clone().into(),
19916                                plain_text: snippet
19917                                    .description
19918                                    .clone()
19919                                    .map(|description| description.into()),
19920                            },
19921                        ),
19922                        insert_text_mode: None,
19923                        confirm: None,
19924                    })
19925                })
19926                .collect();
19927
19928            all_results.append(&mut result);
19929        }
19930
19931        Ok(all_results)
19932    })
19933}
19934
19935impl CompletionProvider for Entity<Project> {
19936    fn completions(
19937        &self,
19938        _excerpt_id: ExcerptId,
19939        buffer: &Entity<Buffer>,
19940        buffer_position: text::Anchor,
19941        options: CompletionContext,
19942        _window: &mut Window,
19943        cx: &mut Context<Editor>,
19944    ) -> Task<Result<Option<Vec<Completion>>>> {
19945        self.update(cx, |project, cx| {
19946            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19947            let project_completions = project.completions(buffer, buffer_position, options, cx);
19948            cx.background_spawn(async move {
19949                let snippets_completions = snippets.await?;
19950                match project_completions.await? {
19951                    Some(mut completions) => {
19952                        completions.extend(snippets_completions);
19953                        Ok(Some(completions))
19954                    }
19955                    None => {
19956                        if snippets_completions.is_empty() {
19957                            Ok(None)
19958                        } else {
19959                            Ok(Some(snippets_completions))
19960                        }
19961                    }
19962                }
19963            })
19964        })
19965    }
19966
19967    fn resolve_completions(
19968        &self,
19969        buffer: Entity<Buffer>,
19970        completion_indices: Vec<usize>,
19971        completions: Rc<RefCell<Box<[Completion]>>>,
19972        cx: &mut Context<Editor>,
19973    ) -> Task<Result<bool>> {
19974        self.update(cx, |project, cx| {
19975            project.lsp_store().update(cx, |lsp_store, cx| {
19976                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19977            })
19978        })
19979    }
19980
19981    fn apply_additional_edits_for_completion(
19982        &self,
19983        buffer: Entity<Buffer>,
19984        completions: Rc<RefCell<Box<[Completion]>>>,
19985        completion_index: usize,
19986        push_to_history: bool,
19987        cx: &mut Context<Editor>,
19988    ) -> Task<Result<Option<language::Transaction>>> {
19989        self.update(cx, |project, cx| {
19990            project.lsp_store().update(cx, |lsp_store, cx| {
19991                lsp_store.apply_additional_edits_for_completion(
19992                    buffer,
19993                    completions,
19994                    completion_index,
19995                    push_to_history,
19996                    cx,
19997                )
19998            })
19999        })
20000    }
20001
20002    fn is_completion_trigger(
20003        &self,
20004        buffer: &Entity<Buffer>,
20005        position: language::Anchor,
20006        text: &str,
20007        trigger_in_words: bool,
20008        cx: &mut Context<Editor>,
20009    ) -> bool {
20010        let mut chars = text.chars();
20011        let char = if let Some(char) = chars.next() {
20012            char
20013        } else {
20014            return false;
20015        };
20016        if chars.next().is_some() {
20017            return false;
20018        }
20019
20020        let buffer = buffer.read(cx);
20021        let snapshot = buffer.snapshot();
20022        if !snapshot.settings_at(position, cx).show_completions_on_input {
20023            return false;
20024        }
20025        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20026        if trigger_in_words && classifier.is_word(char) {
20027            return true;
20028        }
20029
20030        buffer.completion_triggers().contains(text)
20031    }
20032}
20033
20034impl SemanticsProvider for Entity<Project> {
20035    fn hover(
20036        &self,
20037        buffer: &Entity<Buffer>,
20038        position: text::Anchor,
20039        cx: &mut App,
20040    ) -> Option<Task<Vec<project::Hover>>> {
20041        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20042    }
20043
20044    fn document_highlights(
20045        &self,
20046        buffer: &Entity<Buffer>,
20047        position: text::Anchor,
20048        cx: &mut App,
20049    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20050        Some(self.update(cx, |project, cx| {
20051            project.document_highlights(buffer, position, cx)
20052        }))
20053    }
20054
20055    fn definitions(
20056        &self,
20057        buffer: &Entity<Buffer>,
20058        position: text::Anchor,
20059        kind: GotoDefinitionKind,
20060        cx: &mut App,
20061    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20062        Some(self.update(cx, |project, cx| match kind {
20063            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20064            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20065            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20066            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20067        }))
20068    }
20069
20070    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20071        // TODO: make this work for remote projects
20072        self.update(cx, |project, cx| {
20073            if project
20074                .active_debug_session(cx)
20075                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20076            {
20077                return true;
20078            }
20079
20080            buffer.update(cx, |buffer, cx| {
20081                project.any_language_server_supports_inlay_hints(buffer, cx)
20082            })
20083        })
20084    }
20085
20086    fn inline_values(
20087        &self,
20088        buffer_handle: Entity<Buffer>,
20089        range: Range<text::Anchor>,
20090        cx: &mut App,
20091    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20092        self.update(cx, |project, cx| {
20093            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20094
20095            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20096        })
20097    }
20098
20099    fn inlay_hints(
20100        &self,
20101        buffer_handle: Entity<Buffer>,
20102        range: Range<text::Anchor>,
20103        cx: &mut App,
20104    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20105        Some(self.update(cx, |project, cx| {
20106            project.inlay_hints(buffer_handle, range, cx)
20107        }))
20108    }
20109
20110    fn resolve_inlay_hint(
20111        &self,
20112        hint: InlayHint,
20113        buffer_handle: Entity<Buffer>,
20114        server_id: LanguageServerId,
20115        cx: &mut App,
20116    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20117        Some(self.update(cx, |project, cx| {
20118            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20119        }))
20120    }
20121
20122    fn range_for_rename(
20123        &self,
20124        buffer: &Entity<Buffer>,
20125        position: text::Anchor,
20126        cx: &mut App,
20127    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20128        Some(self.update(cx, |project, cx| {
20129            let buffer = buffer.clone();
20130            let task = project.prepare_rename(buffer.clone(), position, cx);
20131            cx.spawn(async move |_, cx| {
20132                Ok(match task.await? {
20133                    PrepareRenameResponse::Success(range) => Some(range),
20134                    PrepareRenameResponse::InvalidPosition => None,
20135                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20136                        // Fallback on using TreeSitter info to determine identifier range
20137                        buffer.update(cx, |buffer, _| {
20138                            let snapshot = buffer.snapshot();
20139                            let (range, kind) = snapshot.surrounding_word(position);
20140                            if kind != Some(CharKind::Word) {
20141                                return None;
20142                            }
20143                            Some(
20144                                snapshot.anchor_before(range.start)
20145                                    ..snapshot.anchor_after(range.end),
20146                            )
20147                        })?
20148                    }
20149                })
20150            })
20151        }))
20152    }
20153
20154    fn perform_rename(
20155        &self,
20156        buffer: &Entity<Buffer>,
20157        position: text::Anchor,
20158        new_name: String,
20159        cx: &mut App,
20160    ) -> Option<Task<Result<ProjectTransaction>>> {
20161        Some(self.update(cx, |project, cx| {
20162            project.perform_rename(buffer.clone(), position, new_name, cx)
20163        }))
20164    }
20165}
20166
20167fn inlay_hint_settings(
20168    location: Anchor,
20169    snapshot: &MultiBufferSnapshot,
20170    cx: &mut Context<Editor>,
20171) -> InlayHintSettings {
20172    let file = snapshot.file_at(location);
20173    let language = snapshot.language_at(location).map(|l| l.name());
20174    language_settings(language, file, cx).inlay_hints
20175}
20176
20177fn consume_contiguous_rows(
20178    contiguous_row_selections: &mut Vec<Selection<Point>>,
20179    selection: &Selection<Point>,
20180    display_map: &DisplaySnapshot,
20181    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20182) -> (MultiBufferRow, MultiBufferRow) {
20183    contiguous_row_selections.push(selection.clone());
20184    let start_row = MultiBufferRow(selection.start.row);
20185    let mut end_row = ending_row(selection, display_map);
20186
20187    while let Some(next_selection) = selections.peek() {
20188        if next_selection.start.row <= end_row.0 {
20189            end_row = ending_row(next_selection, display_map);
20190            contiguous_row_selections.push(selections.next().unwrap().clone());
20191        } else {
20192            break;
20193        }
20194    }
20195    (start_row, end_row)
20196}
20197
20198fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20199    if next_selection.end.column > 0 || next_selection.is_empty() {
20200        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20201    } else {
20202        MultiBufferRow(next_selection.end.row)
20203    }
20204}
20205
20206impl EditorSnapshot {
20207    pub fn remote_selections_in_range<'a>(
20208        &'a self,
20209        range: &'a Range<Anchor>,
20210        collaboration_hub: &dyn CollaborationHub,
20211        cx: &'a App,
20212    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20213        let participant_names = collaboration_hub.user_names(cx);
20214        let participant_indices = collaboration_hub.user_participant_indices(cx);
20215        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20216        let collaborators_by_replica_id = collaborators_by_peer_id
20217            .iter()
20218            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
20219            .collect::<HashMap<_, _>>();
20220        self.buffer_snapshot
20221            .selections_in_range(range, false)
20222            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20223                if replica_id == AGENT_REPLICA_ID {
20224                    Some(RemoteSelection {
20225                        replica_id,
20226                        selection,
20227                        cursor_shape,
20228                        line_mode,
20229                        collaborator_id: CollaboratorId::Agent,
20230                        user_name: Some("Agent".into()),
20231                        color: cx.theme().players().agent(),
20232                    })
20233                } else {
20234                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20235                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20236                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20237                    Some(RemoteSelection {
20238                        replica_id,
20239                        selection,
20240                        cursor_shape,
20241                        line_mode,
20242                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20243                        user_name,
20244                        color: if let Some(index) = participant_index {
20245                            cx.theme().players().color_for_participant(index.0)
20246                        } else {
20247                            cx.theme().players().absent()
20248                        },
20249                    })
20250                }
20251            })
20252    }
20253
20254    pub fn hunks_for_ranges(
20255        &self,
20256        ranges: impl IntoIterator<Item = Range<Point>>,
20257    ) -> Vec<MultiBufferDiffHunk> {
20258        let mut hunks = Vec::new();
20259        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20260            HashMap::default();
20261        for query_range in ranges {
20262            let query_rows =
20263                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20264            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20265                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20266            ) {
20267                // Include deleted hunks that are adjacent to the query range, because
20268                // otherwise they would be missed.
20269                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20270                if hunk.status().is_deleted() {
20271                    intersects_range |= hunk.row_range.start == query_rows.end;
20272                    intersects_range |= hunk.row_range.end == query_rows.start;
20273                }
20274                if intersects_range {
20275                    if !processed_buffer_rows
20276                        .entry(hunk.buffer_id)
20277                        .or_default()
20278                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20279                    {
20280                        continue;
20281                    }
20282                    hunks.push(hunk);
20283                }
20284            }
20285        }
20286
20287        hunks
20288    }
20289
20290    fn display_diff_hunks_for_rows<'a>(
20291        &'a self,
20292        display_rows: Range<DisplayRow>,
20293        folded_buffers: &'a HashSet<BufferId>,
20294    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20295        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20296        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20297
20298        self.buffer_snapshot
20299            .diff_hunks_in_range(buffer_start..buffer_end)
20300            .filter_map(|hunk| {
20301                if folded_buffers.contains(&hunk.buffer_id) {
20302                    return None;
20303                }
20304
20305                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20306                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20307
20308                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20309                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20310
20311                let display_hunk = if hunk_display_start.column() != 0 {
20312                    DisplayDiffHunk::Folded {
20313                        display_row: hunk_display_start.row(),
20314                    }
20315                } else {
20316                    let mut end_row = hunk_display_end.row();
20317                    if hunk_display_end.column() > 0 {
20318                        end_row.0 += 1;
20319                    }
20320                    let is_created_file = hunk.is_created_file();
20321                    DisplayDiffHunk::Unfolded {
20322                        status: hunk.status(),
20323                        diff_base_byte_range: hunk.diff_base_byte_range,
20324                        display_row_range: hunk_display_start.row()..end_row,
20325                        multi_buffer_range: Anchor::range_in_buffer(
20326                            hunk.excerpt_id,
20327                            hunk.buffer_id,
20328                            hunk.buffer_range,
20329                        ),
20330                        is_created_file,
20331                    }
20332                };
20333
20334                Some(display_hunk)
20335            })
20336    }
20337
20338    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20339        self.display_snapshot.buffer_snapshot.language_at(position)
20340    }
20341
20342    pub fn is_focused(&self) -> bool {
20343        self.is_focused
20344    }
20345
20346    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20347        self.placeholder_text.as_ref()
20348    }
20349
20350    pub fn scroll_position(&self) -> gpui::Point<f32> {
20351        self.scroll_anchor.scroll_position(&self.display_snapshot)
20352    }
20353
20354    fn gutter_dimensions(
20355        &self,
20356        font_id: FontId,
20357        font_size: Pixels,
20358        max_line_number_width: Pixels,
20359        cx: &App,
20360    ) -> Option<GutterDimensions> {
20361        if !self.show_gutter {
20362            return None;
20363        }
20364
20365        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20366        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20367
20368        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20369            matches!(
20370                ProjectSettings::get_global(cx).git.git_gutter,
20371                Some(GitGutterSetting::TrackedFiles)
20372            )
20373        });
20374        let gutter_settings = EditorSettings::get_global(cx).gutter;
20375        let show_line_numbers = self
20376            .show_line_numbers
20377            .unwrap_or(gutter_settings.line_numbers);
20378        let line_gutter_width = if show_line_numbers {
20379            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20380            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20381            max_line_number_width.max(min_width_for_number_on_gutter)
20382        } else {
20383            0.0.into()
20384        };
20385
20386        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20387        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20388
20389        let git_blame_entries_width =
20390            self.git_blame_gutter_max_author_length
20391                .map(|max_author_length| {
20392                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20393                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20394
20395                    /// The number of characters to dedicate to gaps and margins.
20396                    const SPACING_WIDTH: usize = 4;
20397
20398                    let max_char_count = max_author_length.min(renderer.max_author_length())
20399                        + ::git::SHORT_SHA_LENGTH
20400                        + MAX_RELATIVE_TIMESTAMP.len()
20401                        + SPACING_WIDTH;
20402
20403                    em_advance * max_char_count
20404                });
20405
20406        let is_singleton = self.buffer_snapshot.is_singleton();
20407
20408        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20409        left_padding += if !is_singleton {
20410            em_width * 4.0
20411        } else if show_runnables || show_breakpoints {
20412            em_width * 3.0
20413        } else if show_git_gutter && show_line_numbers {
20414            em_width * 2.0
20415        } else if show_git_gutter || show_line_numbers {
20416            em_width
20417        } else {
20418            px(0.)
20419        };
20420
20421        let shows_folds = is_singleton && gutter_settings.folds;
20422
20423        let right_padding = if shows_folds && show_line_numbers {
20424            em_width * 4.0
20425        } else if shows_folds || (!is_singleton && show_line_numbers) {
20426            em_width * 3.0
20427        } else if show_line_numbers {
20428            em_width
20429        } else {
20430            px(0.)
20431        };
20432
20433        Some(GutterDimensions {
20434            left_padding,
20435            right_padding,
20436            width: line_gutter_width + left_padding + right_padding,
20437            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20438            git_blame_entries_width,
20439        })
20440    }
20441
20442    pub fn render_crease_toggle(
20443        &self,
20444        buffer_row: MultiBufferRow,
20445        row_contains_cursor: bool,
20446        editor: Entity<Editor>,
20447        window: &mut Window,
20448        cx: &mut App,
20449    ) -> Option<AnyElement> {
20450        let folded = self.is_line_folded(buffer_row);
20451        let mut is_foldable = false;
20452
20453        if let Some(crease) = self
20454            .crease_snapshot
20455            .query_row(buffer_row, &self.buffer_snapshot)
20456        {
20457            is_foldable = true;
20458            match crease {
20459                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20460                    if let Some(render_toggle) = render_toggle {
20461                        let toggle_callback =
20462                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20463                                if folded {
20464                                    editor.update(cx, |editor, cx| {
20465                                        editor.fold_at(buffer_row, window, cx)
20466                                    });
20467                                } else {
20468                                    editor.update(cx, |editor, cx| {
20469                                        editor.unfold_at(buffer_row, window, cx)
20470                                    });
20471                                }
20472                            });
20473                        return Some((render_toggle)(
20474                            buffer_row,
20475                            folded,
20476                            toggle_callback,
20477                            window,
20478                            cx,
20479                        ));
20480                    }
20481                }
20482            }
20483        }
20484
20485        is_foldable |= self.starts_indent(buffer_row);
20486
20487        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20488            Some(
20489                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20490                    .toggle_state(folded)
20491                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20492                        if folded {
20493                            this.unfold_at(buffer_row, window, cx);
20494                        } else {
20495                            this.fold_at(buffer_row, window, cx);
20496                        }
20497                    }))
20498                    .into_any_element(),
20499            )
20500        } else {
20501            None
20502        }
20503    }
20504
20505    pub fn render_crease_trailer(
20506        &self,
20507        buffer_row: MultiBufferRow,
20508        window: &mut Window,
20509        cx: &mut App,
20510    ) -> Option<AnyElement> {
20511        let folded = self.is_line_folded(buffer_row);
20512        if let Crease::Inline { render_trailer, .. } = self
20513            .crease_snapshot
20514            .query_row(buffer_row, &self.buffer_snapshot)?
20515        {
20516            let render_trailer = render_trailer.as_ref()?;
20517            Some(render_trailer(buffer_row, folded, window, cx))
20518        } else {
20519            None
20520        }
20521    }
20522}
20523
20524impl Deref for EditorSnapshot {
20525    type Target = DisplaySnapshot;
20526
20527    fn deref(&self) -> &Self::Target {
20528        &self.display_snapshot
20529    }
20530}
20531
20532#[derive(Clone, Debug, PartialEq, Eq)]
20533pub enum EditorEvent {
20534    InputIgnored {
20535        text: Arc<str>,
20536    },
20537    InputHandled {
20538        utf16_range_to_replace: Option<Range<isize>>,
20539        text: Arc<str>,
20540    },
20541    ExcerptsAdded {
20542        buffer: Entity<Buffer>,
20543        predecessor: ExcerptId,
20544        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20545    },
20546    ExcerptsRemoved {
20547        ids: Vec<ExcerptId>,
20548        removed_buffer_ids: Vec<BufferId>,
20549    },
20550    BufferFoldToggled {
20551        ids: Vec<ExcerptId>,
20552        folded: bool,
20553    },
20554    ExcerptsEdited {
20555        ids: Vec<ExcerptId>,
20556    },
20557    ExcerptsExpanded {
20558        ids: Vec<ExcerptId>,
20559    },
20560    BufferEdited,
20561    Edited {
20562        transaction_id: clock::Lamport,
20563    },
20564    Reparsed(BufferId),
20565    Focused,
20566    FocusedIn,
20567    Blurred,
20568    DirtyChanged,
20569    Saved,
20570    TitleChanged,
20571    DiffBaseChanged,
20572    SelectionsChanged {
20573        local: bool,
20574    },
20575    ScrollPositionChanged {
20576        local: bool,
20577        autoscroll: bool,
20578    },
20579    Closed,
20580    TransactionUndone {
20581        transaction_id: clock::Lamport,
20582    },
20583    TransactionBegun {
20584        transaction_id: clock::Lamport,
20585    },
20586    Reloaded,
20587    CursorShapeChanged,
20588    PushedToNavHistory {
20589        anchor: Anchor,
20590        is_deactivate: bool,
20591    },
20592}
20593
20594impl EventEmitter<EditorEvent> for Editor {}
20595
20596impl Focusable for Editor {
20597    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20598        self.focus_handle.clone()
20599    }
20600}
20601
20602impl Render for Editor {
20603    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20604        let settings = ThemeSettings::get_global(cx);
20605
20606        let mut text_style = match self.mode {
20607            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20608                color: cx.theme().colors().editor_foreground,
20609                font_family: settings.ui_font.family.clone(),
20610                font_features: settings.ui_font.features.clone(),
20611                font_fallbacks: settings.ui_font.fallbacks.clone(),
20612                font_size: rems(0.875).into(),
20613                font_weight: settings.ui_font.weight,
20614                line_height: relative(settings.buffer_line_height.value()),
20615                ..Default::default()
20616            },
20617            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20618                color: cx.theme().colors().editor_foreground,
20619                font_family: settings.buffer_font.family.clone(),
20620                font_features: settings.buffer_font.features.clone(),
20621                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20622                font_size: settings.buffer_font_size(cx).into(),
20623                font_weight: settings.buffer_font.weight,
20624                line_height: relative(settings.buffer_line_height.value()),
20625                ..Default::default()
20626            },
20627        };
20628        if let Some(text_style_refinement) = &self.text_style_refinement {
20629            text_style.refine(text_style_refinement)
20630        }
20631
20632        let background = match self.mode {
20633            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20634            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20635            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20636            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20637        };
20638
20639        EditorElement::new(
20640            &cx.entity(),
20641            EditorStyle {
20642                background,
20643                local_player: cx.theme().players().local(),
20644                text: text_style,
20645                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20646                syntax: cx.theme().syntax().clone(),
20647                status: cx.theme().status().clone(),
20648                inlay_hints_style: make_inlay_hints_style(cx),
20649                inline_completion_styles: make_suggestion_styles(cx),
20650                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20651                show_underlines: !self.mode.is_minimap(),
20652            },
20653        )
20654    }
20655}
20656
20657impl EntityInputHandler for Editor {
20658    fn text_for_range(
20659        &mut self,
20660        range_utf16: Range<usize>,
20661        adjusted_range: &mut Option<Range<usize>>,
20662        _: &mut Window,
20663        cx: &mut Context<Self>,
20664    ) -> Option<String> {
20665        let snapshot = self.buffer.read(cx).read(cx);
20666        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20667        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20668        if (start.0..end.0) != range_utf16 {
20669            adjusted_range.replace(start.0..end.0);
20670        }
20671        Some(snapshot.text_for_range(start..end).collect())
20672    }
20673
20674    fn selected_text_range(
20675        &mut self,
20676        ignore_disabled_input: bool,
20677        _: &mut Window,
20678        cx: &mut Context<Self>,
20679    ) -> Option<UTF16Selection> {
20680        // Prevent the IME menu from appearing when holding down an alphabetic key
20681        // while input is disabled.
20682        if !ignore_disabled_input && !self.input_enabled {
20683            return None;
20684        }
20685
20686        let selection = self.selections.newest::<OffsetUtf16>(cx);
20687        let range = selection.range();
20688
20689        Some(UTF16Selection {
20690            range: range.start.0..range.end.0,
20691            reversed: selection.reversed,
20692        })
20693    }
20694
20695    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20696        let snapshot = self.buffer.read(cx).read(cx);
20697        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20698        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20699    }
20700
20701    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20702        self.clear_highlights::<InputComposition>(cx);
20703        self.ime_transaction.take();
20704    }
20705
20706    fn replace_text_in_range(
20707        &mut self,
20708        range_utf16: Option<Range<usize>>,
20709        text: &str,
20710        window: &mut Window,
20711        cx: &mut Context<Self>,
20712    ) {
20713        if !self.input_enabled {
20714            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20715            return;
20716        }
20717
20718        self.transact(window, cx, |this, window, cx| {
20719            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20720                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20721                Some(this.selection_replacement_ranges(range_utf16, cx))
20722            } else {
20723                this.marked_text_ranges(cx)
20724            };
20725
20726            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20727                let newest_selection_id = this.selections.newest_anchor().id;
20728                this.selections
20729                    .all::<OffsetUtf16>(cx)
20730                    .iter()
20731                    .zip(ranges_to_replace.iter())
20732                    .find_map(|(selection, range)| {
20733                        if selection.id == newest_selection_id {
20734                            Some(
20735                                (range.start.0 as isize - selection.head().0 as isize)
20736                                    ..(range.end.0 as isize - selection.head().0 as isize),
20737                            )
20738                        } else {
20739                            None
20740                        }
20741                    })
20742            });
20743
20744            cx.emit(EditorEvent::InputHandled {
20745                utf16_range_to_replace: range_to_replace,
20746                text: text.into(),
20747            });
20748
20749            if let Some(new_selected_ranges) = new_selected_ranges {
20750                this.change_selections(None, window, cx, |selections| {
20751                    selections.select_ranges(new_selected_ranges)
20752                });
20753                this.backspace(&Default::default(), window, cx);
20754            }
20755
20756            this.handle_input(text, window, cx);
20757        });
20758
20759        if let Some(transaction) = self.ime_transaction {
20760            self.buffer.update(cx, |buffer, cx| {
20761                buffer.group_until_transaction(transaction, cx);
20762            });
20763        }
20764
20765        self.unmark_text(window, cx);
20766    }
20767
20768    fn replace_and_mark_text_in_range(
20769        &mut self,
20770        range_utf16: Option<Range<usize>>,
20771        text: &str,
20772        new_selected_range_utf16: Option<Range<usize>>,
20773        window: &mut Window,
20774        cx: &mut Context<Self>,
20775    ) {
20776        if !self.input_enabled {
20777            return;
20778        }
20779
20780        let transaction = self.transact(window, cx, |this, window, cx| {
20781            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20782                let snapshot = this.buffer.read(cx).read(cx);
20783                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20784                    for marked_range in &mut marked_ranges {
20785                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20786                        marked_range.start.0 += relative_range_utf16.start;
20787                        marked_range.start =
20788                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20789                        marked_range.end =
20790                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20791                    }
20792                }
20793                Some(marked_ranges)
20794            } else if let Some(range_utf16) = range_utf16 {
20795                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20796                Some(this.selection_replacement_ranges(range_utf16, cx))
20797            } else {
20798                None
20799            };
20800
20801            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20802                let newest_selection_id = this.selections.newest_anchor().id;
20803                this.selections
20804                    .all::<OffsetUtf16>(cx)
20805                    .iter()
20806                    .zip(ranges_to_replace.iter())
20807                    .find_map(|(selection, range)| {
20808                        if selection.id == newest_selection_id {
20809                            Some(
20810                                (range.start.0 as isize - selection.head().0 as isize)
20811                                    ..(range.end.0 as isize - selection.head().0 as isize),
20812                            )
20813                        } else {
20814                            None
20815                        }
20816                    })
20817            });
20818
20819            cx.emit(EditorEvent::InputHandled {
20820                utf16_range_to_replace: range_to_replace,
20821                text: text.into(),
20822            });
20823
20824            if let Some(ranges) = ranges_to_replace {
20825                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20826            }
20827
20828            let marked_ranges = {
20829                let snapshot = this.buffer.read(cx).read(cx);
20830                this.selections
20831                    .disjoint_anchors()
20832                    .iter()
20833                    .map(|selection| {
20834                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20835                    })
20836                    .collect::<Vec<_>>()
20837            };
20838
20839            if text.is_empty() {
20840                this.unmark_text(window, cx);
20841            } else {
20842                this.highlight_text::<InputComposition>(
20843                    marked_ranges.clone(),
20844                    HighlightStyle {
20845                        underline: Some(UnderlineStyle {
20846                            thickness: px(1.),
20847                            color: None,
20848                            wavy: false,
20849                        }),
20850                        ..Default::default()
20851                    },
20852                    cx,
20853                );
20854            }
20855
20856            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20857            let use_autoclose = this.use_autoclose;
20858            let use_auto_surround = this.use_auto_surround;
20859            this.set_use_autoclose(false);
20860            this.set_use_auto_surround(false);
20861            this.handle_input(text, window, cx);
20862            this.set_use_autoclose(use_autoclose);
20863            this.set_use_auto_surround(use_auto_surround);
20864
20865            if let Some(new_selected_range) = new_selected_range_utf16 {
20866                let snapshot = this.buffer.read(cx).read(cx);
20867                let new_selected_ranges = marked_ranges
20868                    .into_iter()
20869                    .map(|marked_range| {
20870                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20871                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20872                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20873                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20874                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20875                    })
20876                    .collect::<Vec<_>>();
20877
20878                drop(snapshot);
20879                this.change_selections(None, window, cx, |selections| {
20880                    selections.select_ranges(new_selected_ranges)
20881                });
20882            }
20883        });
20884
20885        self.ime_transaction = self.ime_transaction.or(transaction);
20886        if let Some(transaction) = self.ime_transaction {
20887            self.buffer.update(cx, |buffer, cx| {
20888                buffer.group_until_transaction(transaction, cx);
20889            });
20890        }
20891
20892        if self.text_highlights::<InputComposition>(cx).is_none() {
20893            self.ime_transaction.take();
20894        }
20895    }
20896
20897    fn bounds_for_range(
20898        &mut self,
20899        range_utf16: Range<usize>,
20900        element_bounds: gpui::Bounds<Pixels>,
20901        window: &mut Window,
20902        cx: &mut Context<Self>,
20903    ) -> Option<gpui::Bounds<Pixels>> {
20904        let text_layout_details = self.text_layout_details(window);
20905        let gpui::Size {
20906            width: em_width,
20907            height: line_height,
20908        } = self.character_size(window);
20909
20910        let snapshot = self.snapshot(window, cx);
20911        let scroll_position = snapshot.scroll_position();
20912        let scroll_left = scroll_position.x * em_width;
20913
20914        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20915        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20916            + self.gutter_dimensions.width
20917            + self.gutter_dimensions.margin;
20918        let y = line_height * (start.row().as_f32() - scroll_position.y);
20919
20920        Some(Bounds {
20921            origin: element_bounds.origin + point(x, y),
20922            size: size(em_width, line_height),
20923        })
20924    }
20925
20926    fn character_index_for_point(
20927        &mut self,
20928        point: gpui::Point<Pixels>,
20929        _window: &mut Window,
20930        _cx: &mut Context<Self>,
20931    ) -> Option<usize> {
20932        let position_map = self.last_position_map.as_ref()?;
20933        if !position_map.text_hitbox.contains(&point) {
20934            return None;
20935        }
20936        let display_point = position_map.point_for_position(point).previous_valid;
20937        let anchor = position_map
20938            .snapshot
20939            .display_point_to_anchor(display_point, Bias::Left);
20940        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20941        Some(utf16_offset.0)
20942    }
20943}
20944
20945trait SelectionExt {
20946    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20947    fn spanned_rows(
20948        &self,
20949        include_end_if_at_line_start: bool,
20950        map: &DisplaySnapshot,
20951    ) -> Range<MultiBufferRow>;
20952}
20953
20954impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20955    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20956        let start = self
20957            .start
20958            .to_point(&map.buffer_snapshot)
20959            .to_display_point(map);
20960        let end = self
20961            .end
20962            .to_point(&map.buffer_snapshot)
20963            .to_display_point(map);
20964        if self.reversed {
20965            end..start
20966        } else {
20967            start..end
20968        }
20969    }
20970
20971    fn spanned_rows(
20972        &self,
20973        include_end_if_at_line_start: bool,
20974        map: &DisplaySnapshot,
20975    ) -> Range<MultiBufferRow> {
20976        let start = self.start.to_point(&map.buffer_snapshot);
20977        let mut end = self.end.to_point(&map.buffer_snapshot);
20978        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20979            end.row -= 1;
20980        }
20981
20982        let buffer_start = map.prev_line_boundary(start).0;
20983        let buffer_end = map.next_line_boundary(end).0;
20984        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20985    }
20986}
20987
20988impl<T: InvalidationRegion> InvalidationStack<T> {
20989    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20990    where
20991        S: Clone + ToOffset,
20992    {
20993        while let Some(region) = self.last() {
20994            let all_selections_inside_invalidation_ranges =
20995                if selections.len() == region.ranges().len() {
20996                    selections
20997                        .iter()
20998                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20999                        .all(|(selection, invalidation_range)| {
21000                            let head = selection.head().to_offset(buffer);
21001                            invalidation_range.start <= head && invalidation_range.end >= head
21002                        })
21003                } else {
21004                    false
21005                };
21006
21007            if all_selections_inside_invalidation_ranges {
21008                break;
21009            } else {
21010                self.pop();
21011            }
21012        }
21013    }
21014}
21015
21016impl<T> Default for InvalidationStack<T> {
21017    fn default() -> Self {
21018        Self(Default::default())
21019    }
21020}
21021
21022impl<T> Deref for InvalidationStack<T> {
21023    type Target = Vec<T>;
21024
21025    fn deref(&self) -> &Self::Target {
21026        &self.0
21027    }
21028}
21029
21030impl<T> DerefMut for InvalidationStack<T> {
21031    fn deref_mut(&mut self) -> &mut Self::Target {
21032        &mut self.0
21033    }
21034}
21035
21036impl InvalidationRegion for SnippetState {
21037    fn ranges(&self) -> &[Range<Anchor>] {
21038        &self.ranges[self.active_index]
21039    }
21040}
21041
21042fn inline_completion_edit_text(
21043    current_snapshot: &BufferSnapshot,
21044    edits: &[(Range<Anchor>, String)],
21045    edit_preview: &EditPreview,
21046    include_deletions: bool,
21047    cx: &App,
21048) -> HighlightedText {
21049    let edits = edits
21050        .iter()
21051        .map(|(anchor, text)| {
21052            (
21053                anchor.start.text_anchor..anchor.end.text_anchor,
21054                text.clone(),
21055            )
21056        })
21057        .collect::<Vec<_>>();
21058
21059    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21060}
21061
21062pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21063    match severity {
21064        lsp::DiagnosticSeverity::ERROR => colors.error,
21065        lsp::DiagnosticSeverity::WARNING => colors.warning,
21066        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21067        lsp::DiagnosticSeverity::HINT => colors.info,
21068        _ => colors.ignored,
21069    }
21070}
21071
21072pub fn styled_runs_for_code_label<'a>(
21073    label: &'a CodeLabel,
21074    syntax_theme: &'a theme::SyntaxTheme,
21075) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21076    let fade_out = HighlightStyle {
21077        fade_out: Some(0.35),
21078        ..Default::default()
21079    };
21080
21081    let mut prev_end = label.filter_range.end;
21082    label
21083        .runs
21084        .iter()
21085        .enumerate()
21086        .flat_map(move |(ix, (range, highlight_id))| {
21087            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21088                style
21089            } else {
21090                return Default::default();
21091            };
21092            let mut muted_style = style;
21093            muted_style.highlight(fade_out);
21094
21095            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21096            if range.start >= label.filter_range.end {
21097                if range.start > prev_end {
21098                    runs.push((prev_end..range.start, fade_out));
21099                }
21100                runs.push((range.clone(), muted_style));
21101            } else if range.end <= label.filter_range.end {
21102                runs.push((range.clone(), style));
21103            } else {
21104                runs.push((range.start..label.filter_range.end, style));
21105                runs.push((label.filter_range.end..range.end, muted_style));
21106            }
21107            prev_end = cmp::max(prev_end, range.end);
21108
21109            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21110                runs.push((prev_end..label.text.len(), fade_out));
21111            }
21112
21113            runs
21114        })
21115}
21116
21117pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21118    let mut prev_index = 0;
21119    let mut prev_codepoint: Option<char> = None;
21120    text.char_indices()
21121        .chain([(text.len(), '\0')])
21122        .filter_map(move |(index, codepoint)| {
21123            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21124            let is_boundary = index == text.len()
21125                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21126                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21127            if is_boundary {
21128                let chunk = &text[prev_index..index];
21129                prev_index = index;
21130                Some(chunk)
21131            } else {
21132                None
21133            }
21134        })
21135}
21136
21137pub trait RangeToAnchorExt: Sized {
21138    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21139
21140    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21141        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21142        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21143    }
21144}
21145
21146impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21147    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21148        let start_offset = self.start.to_offset(snapshot);
21149        let end_offset = self.end.to_offset(snapshot);
21150        if start_offset == end_offset {
21151            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21152        } else {
21153            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21154        }
21155    }
21156}
21157
21158pub trait RowExt {
21159    fn as_f32(&self) -> f32;
21160
21161    fn next_row(&self) -> Self;
21162
21163    fn previous_row(&self) -> Self;
21164
21165    fn minus(&self, other: Self) -> u32;
21166}
21167
21168impl RowExt for DisplayRow {
21169    fn as_f32(&self) -> f32 {
21170        self.0 as f32
21171    }
21172
21173    fn next_row(&self) -> Self {
21174        Self(self.0 + 1)
21175    }
21176
21177    fn previous_row(&self) -> Self {
21178        Self(self.0.saturating_sub(1))
21179    }
21180
21181    fn minus(&self, other: Self) -> u32 {
21182        self.0 - other.0
21183    }
21184}
21185
21186impl RowExt for MultiBufferRow {
21187    fn as_f32(&self) -> f32 {
21188        self.0 as f32
21189    }
21190
21191    fn next_row(&self) -> Self {
21192        Self(self.0 + 1)
21193    }
21194
21195    fn previous_row(&self) -> Self {
21196        Self(self.0.saturating_sub(1))
21197    }
21198
21199    fn minus(&self, other: Self) -> u32 {
21200        self.0 - other.0
21201    }
21202}
21203
21204trait RowRangeExt {
21205    type Row;
21206
21207    fn len(&self) -> usize;
21208
21209    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21210}
21211
21212impl RowRangeExt for Range<MultiBufferRow> {
21213    type Row = MultiBufferRow;
21214
21215    fn len(&self) -> usize {
21216        (self.end.0 - self.start.0) as usize
21217    }
21218
21219    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21220        (self.start.0..self.end.0).map(MultiBufferRow)
21221    }
21222}
21223
21224impl RowRangeExt for Range<DisplayRow> {
21225    type Row = DisplayRow;
21226
21227    fn len(&self) -> usize {
21228        (self.end.0 - self.start.0) as usize
21229    }
21230
21231    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21232        (self.start.0..self.end.0).map(DisplayRow)
21233    }
21234}
21235
21236/// If select range has more than one line, we
21237/// just point the cursor to range.start.
21238fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21239    if range.start.row == range.end.row {
21240        range
21241    } else {
21242        range.start..range.start
21243    }
21244}
21245pub struct KillRing(ClipboardItem);
21246impl Global for KillRing {}
21247
21248const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21249
21250enum BreakpointPromptEditAction {
21251    Log,
21252    Condition,
21253    HitCondition,
21254}
21255
21256struct BreakpointPromptEditor {
21257    pub(crate) prompt: Entity<Editor>,
21258    editor: WeakEntity<Editor>,
21259    breakpoint_anchor: Anchor,
21260    breakpoint: Breakpoint,
21261    edit_action: BreakpointPromptEditAction,
21262    block_ids: HashSet<CustomBlockId>,
21263    editor_margins: Arc<Mutex<EditorMargins>>,
21264    _subscriptions: Vec<Subscription>,
21265}
21266
21267impl BreakpointPromptEditor {
21268    const MAX_LINES: u8 = 4;
21269
21270    fn new(
21271        editor: WeakEntity<Editor>,
21272        breakpoint_anchor: Anchor,
21273        breakpoint: Breakpoint,
21274        edit_action: BreakpointPromptEditAction,
21275        window: &mut Window,
21276        cx: &mut Context<Self>,
21277    ) -> Self {
21278        let base_text = match edit_action {
21279            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21280            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21281            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21282        }
21283        .map(|msg| msg.to_string())
21284        .unwrap_or_default();
21285
21286        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21287        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21288
21289        let prompt = cx.new(|cx| {
21290            let mut prompt = Editor::new(
21291                EditorMode::AutoHeight {
21292                    max_lines: Self::MAX_LINES as usize,
21293                },
21294                buffer,
21295                None,
21296                window,
21297                cx,
21298            );
21299            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21300            prompt.set_show_cursor_when_unfocused(false, cx);
21301            prompt.set_placeholder_text(
21302                match edit_action {
21303                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21304                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21305                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21306                },
21307                cx,
21308            );
21309
21310            prompt
21311        });
21312
21313        Self {
21314            prompt,
21315            editor,
21316            breakpoint_anchor,
21317            breakpoint,
21318            edit_action,
21319            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21320            block_ids: Default::default(),
21321            _subscriptions: vec![],
21322        }
21323    }
21324
21325    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21326        self.block_ids.extend(block_ids)
21327    }
21328
21329    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21330        if let Some(editor) = self.editor.upgrade() {
21331            let message = self
21332                .prompt
21333                .read(cx)
21334                .buffer
21335                .read(cx)
21336                .as_singleton()
21337                .expect("A multi buffer in breakpoint prompt isn't possible")
21338                .read(cx)
21339                .as_rope()
21340                .to_string();
21341
21342            editor.update(cx, |editor, cx| {
21343                editor.edit_breakpoint_at_anchor(
21344                    self.breakpoint_anchor,
21345                    self.breakpoint.clone(),
21346                    match self.edit_action {
21347                        BreakpointPromptEditAction::Log => {
21348                            BreakpointEditAction::EditLogMessage(message.into())
21349                        }
21350                        BreakpointPromptEditAction::Condition => {
21351                            BreakpointEditAction::EditCondition(message.into())
21352                        }
21353                        BreakpointPromptEditAction::HitCondition => {
21354                            BreakpointEditAction::EditHitCondition(message.into())
21355                        }
21356                    },
21357                    cx,
21358                );
21359
21360                editor.remove_blocks(self.block_ids.clone(), None, cx);
21361                cx.focus_self(window);
21362            });
21363        }
21364    }
21365
21366    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21367        self.editor
21368            .update(cx, |editor, cx| {
21369                editor.remove_blocks(self.block_ids.clone(), None, cx);
21370                window.focus(&editor.focus_handle);
21371            })
21372            .log_err();
21373    }
21374
21375    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21376        let settings = ThemeSettings::get_global(cx);
21377        let text_style = TextStyle {
21378            color: if self.prompt.read(cx).read_only(cx) {
21379                cx.theme().colors().text_disabled
21380            } else {
21381                cx.theme().colors().text
21382            },
21383            font_family: settings.buffer_font.family.clone(),
21384            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21385            font_size: settings.buffer_font_size(cx).into(),
21386            font_weight: settings.buffer_font.weight,
21387            line_height: relative(settings.buffer_line_height.value()),
21388            ..Default::default()
21389        };
21390        EditorElement::new(
21391            &self.prompt,
21392            EditorStyle {
21393                background: cx.theme().colors().editor_background,
21394                local_player: cx.theme().players().local(),
21395                text: text_style,
21396                ..Default::default()
21397            },
21398        )
21399    }
21400}
21401
21402impl Render for BreakpointPromptEditor {
21403    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21404        let editor_margins = *self.editor_margins.lock();
21405        let gutter_dimensions = editor_margins.gutter;
21406        h_flex()
21407            .key_context("Editor")
21408            .bg(cx.theme().colors().editor_background)
21409            .border_y_1()
21410            .border_color(cx.theme().status().info_border)
21411            .size_full()
21412            .py(window.line_height() / 2.5)
21413            .on_action(cx.listener(Self::confirm))
21414            .on_action(cx.listener(Self::cancel))
21415            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21416            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21417    }
21418}
21419
21420impl Focusable for BreakpointPromptEditor {
21421    fn focus_handle(&self, cx: &App) -> FocusHandle {
21422        self.prompt.focus_handle(cx)
21423    }
21424}
21425
21426fn all_edits_insertions_or_deletions(
21427    edits: &Vec<(Range<Anchor>, String)>,
21428    snapshot: &MultiBufferSnapshot,
21429) -> bool {
21430    let mut all_insertions = true;
21431    let mut all_deletions = true;
21432
21433    for (range, new_text) in edits.iter() {
21434        let range_is_empty = range.to_offset(&snapshot).is_empty();
21435        let text_is_empty = new_text.is_empty();
21436
21437        if range_is_empty != text_is_empty {
21438            if range_is_empty {
21439                all_deletions = false;
21440            } else {
21441                all_insertions = false;
21442            }
21443        } else {
21444            return false;
21445        }
21446
21447        if !all_insertions && !all_deletions {
21448            return false;
21449        }
21450    }
21451    all_insertions || all_deletions
21452}
21453
21454struct MissingEditPredictionKeybindingTooltip;
21455
21456impl Render for MissingEditPredictionKeybindingTooltip {
21457    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21458        ui::tooltip_container(window, cx, |container, _, cx| {
21459            container
21460                .flex_shrink_0()
21461                .max_w_80()
21462                .min_h(rems_from_px(124.))
21463                .justify_between()
21464                .child(
21465                    v_flex()
21466                        .flex_1()
21467                        .text_ui_sm(cx)
21468                        .child(Label::new("Conflict with Accept Keybinding"))
21469                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21470                )
21471                .child(
21472                    h_flex()
21473                        .pb_1()
21474                        .gap_1()
21475                        .items_end()
21476                        .w_full()
21477                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21478                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21479                        }))
21480                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21481                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21482                        })),
21483                )
21484        })
21485    }
21486}
21487
21488#[derive(Debug, Clone, Copy, PartialEq)]
21489pub struct LineHighlight {
21490    pub background: Background,
21491    pub border: Option<gpui::Hsla>,
21492    pub include_gutter: bool,
21493    pub type_id: Option<TypeId>,
21494}
21495
21496fn render_diff_hunk_controls(
21497    row: u32,
21498    status: &DiffHunkStatus,
21499    hunk_range: Range<Anchor>,
21500    is_created_file: bool,
21501    line_height: Pixels,
21502    editor: &Entity<Editor>,
21503    _window: &mut Window,
21504    cx: &mut App,
21505) -> AnyElement {
21506    h_flex()
21507        .h(line_height)
21508        .mr_1()
21509        .gap_1()
21510        .px_0p5()
21511        .pb_1()
21512        .border_x_1()
21513        .border_b_1()
21514        .border_color(cx.theme().colors().border_variant)
21515        .rounded_b_lg()
21516        .bg(cx.theme().colors().editor_background)
21517        .gap_1()
21518        .occlude()
21519        .shadow_md()
21520        .child(if status.has_secondary_hunk() {
21521            Button::new(("stage", row as u64), "Stage")
21522                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21523                .tooltip({
21524                    let focus_handle = editor.focus_handle(cx);
21525                    move |window, cx| {
21526                        Tooltip::for_action_in(
21527                            "Stage Hunk",
21528                            &::git::ToggleStaged,
21529                            &focus_handle,
21530                            window,
21531                            cx,
21532                        )
21533                    }
21534                })
21535                .on_click({
21536                    let editor = editor.clone();
21537                    move |_event, _window, cx| {
21538                        editor.update(cx, |editor, cx| {
21539                            editor.stage_or_unstage_diff_hunks(
21540                                true,
21541                                vec![hunk_range.start..hunk_range.start],
21542                                cx,
21543                            );
21544                        });
21545                    }
21546                })
21547        } else {
21548            Button::new(("unstage", row as u64), "Unstage")
21549                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21550                .tooltip({
21551                    let focus_handle = editor.focus_handle(cx);
21552                    move |window, cx| {
21553                        Tooltip::for_action_in(
21554                            "Unstage Hunk",
21555                            &::git::ToggleStaged,
21556                            &focus_handle,
21557                            window,
21558                            cx,
21559                        )
21560                    }
21561                })
21562                .on_click({
21563                    let editor = editor.clone();
21564                    move |_event, _window, cx| {
21565                        editor.update(cx, |editor, cx| {
21566                            editor.stage_or_unstage_diff_hunks(
21567                                false,
21568                                vec![hunk_range.start..hunk_range.start],
21569                                cx,
21570                            );
21571                        });
21572                    }
21573                })
21574        })
21575        .child(
21576            Button::new(("restore", row as u64), "Restore")
21577                .tooltip({
21578                    let focus_handle = editor.focus_handle(cx);
21579                    move |window, cx| {
21580                        Tooltip::for_action_in(
21581                            "Restore Hunk",
21582                            &::git::Restore,
21583                            &focus_handle,
21584                            window,
21585                            cx,
21586                        )
21587                    }
21588                })
21589                .on_click({
21590                    let editor = editor.clone();
21591                    move |_event, window, cx| {
21592                        editor.update(cx, |editor, cx| {
21593                            let snapshot = editor.snapshot(window, cx);
21594                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21595                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21596                        });
21597                    }
21598                })
21599                .disabled(is_created_file),
21600        )
21601        .when(
21602            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21603            |el| {
21604                el.child(
21605                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21606                        .shape(IconButtonShape::Square)
21607                        .icon_size(IconSize::Small)
21608                        // .disabled(!has_multiple_hunks)
21609                        .tooltip({
21610                            let focus_handle = editor.focus_handle(cx);
21611                            move |window, cx| {
21612                                Tooltip::for_action_in(
21613                                    "Next Hunk",
21614                                    &GoToHunk,
21615                                    &focus_handle,
21616                                    window,
21617                                    cx,
21618                                )
21619                            }
21620                        })
21621                        .on_click({
21622                            let editor = editor.clone();
21623                            move |_event, window, cx| {
21624                                editor.update(cx, |editor, cx| {
21625                                    let snapshot = editor.snapshot(window, cx);
21626                                    let position =
21627                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21628                                    editor.go_to_hunk_before_or_after_position(
21629                                        &snapshot,
21630                                        position,
21631                                        Direction::Next,
21632                                        window,
21633                                        cx,
21634                                    );
21635                                    editor.expand_selected_diff_hunks(cx);
21636                                });
21637                            }
21638                        }),
21639                )
21640                .child(
21641                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21642                        .shape(IconButtonShape::Square)
21643                        .icon_size(IconSize::Small)
21644                        // .disabled(!has_multiple_hunks)
21645                        .tooltip({
21646                            let focus_handle = editor.focus_handle(cx);
21647                            move |window, cx| {
21648                                Tooltip::for_action_in(
21649                                    "Previous Hunk",
21650                                    &GoToPreviousHunk,
21651                                    &focus_handle,
21652                                    window,
21653                                    cx,
21654                                )
21655                            }
21656                        })
21657                        .on_click({
21658                            let editor = editor.clone();
21659                            move |_event, window, cx| {
21660                                editor.update(cx, |editor, cx| {
21661                                    let snapshot = editor.snapshot(window, cx);
21662                                    let point =
21663                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21664                                    editor.go_to_hunk_before_or_after_position(
21665                                        &snapshot,
21666                                        point,
21667                                        Direction::Prev,
21668                                        window,
21669                                        cx,
21670                                    );
21671                                    editor.expand_selected_diff_hunks(cx);
21672                                });
21673                            }
21674                        }),
21675                )
21676            },
21677        )
21678        .into_any_element()
21679}