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::ReplicaId;
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64use editor_settings::GoToDefinitionFallback;
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   67    ShowScrollbar,
   68};
   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    ProjectPath,
  126    debugger::{
  127        breakpoint_store::{
  128            BreakpointEditAction, BreakpointState, BreakpointStore, BreakpointStoreEvent,
  129        },
  130        session::{Session, SessionEvent},
  131    },
  132};
  133
  134pub use git::blame::BlameRenderer;
  135pub use proposed_changes_editor::{
  136    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  137};
  138use smallvec::smallvec;
  139use std::{cell::OnceCell, iter::Peekable};
  140use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  141
  142pub use lsp::CompletionContext;
  143use lsp::{
  144    CodeActionKind, CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity,
  145    InsertTextFormat, InsertTextMode, LanguageServerId, LanguageServerName,
  146};
  147
  148use language::BufferSnapshot;
  149pub use lsp_ext::lsp_tasks;
  150use movement::TextLayoutDetails;
  151pub use multi_buffer::{
  152    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  153    RowInfo, ToOffset, ToPoint,
  154};
  155use multi_buffer::{
  156    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  157    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  158};
  159use parking_lot::Mutex;
  160use project::{
  161    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  162    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  163    TaskSourceKind,
  164    debugger::breakpoint_store::Breakpoint,
  165    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  166    project_settings::{GitGutterSetting, ProjectSettings},
  167};
  168use rand::prelude::*;
  169use rpc::{ErrorExt, proto::*};
  170use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  171use selections_collection::{
  172    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  173};
  174use serde::{Deserialize, Serialize};
  175use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  176use smallvec::SmallVec;
  177use snippet::Snippet;
  178use std::sync::Arc;
  179use std::{
  180    any::TypeId,
  181    borrow::Cow,
  182    cell::RefCell,
  183    cmp::{self, Ordering, Reverse},
  184    mem,
  185    num::NonZeroU32,
  186    ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    time::{Duration, Instant},
  190};
  191pub use sum_tree::Bias;
  192use sum_tree::TreeMap;
  193use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  194use theme::{
  195    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  196    observe_buffer_font_size_adjustment,
  197};
  198use ui::{
  199    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  200    IconSize, Key, Tooltip, h_flex, prelude::*,
  201};
  202use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  203use workspace::{
  204    Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  205    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  206    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  207    item::{ItemHandle, PreviewTabsSettings},
  208    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  209    searchable::SearchEvent,
  210};
  211
  212use crate::hover_links::{find_url, find_url_from_range};
  213use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  249    alt: true,
  250    shift: true,
  251    control: false,
  252    platform: false,
  253    function: false,
  254};
  255
  256struct InlineValueCache {
  257    enabled: bool,
  258    inlays: Vec<InlayId>,
  259    refresh_task: Task<Option<()>>,
  260}
  261
  262impl InlineValueCache {
  263    fn new(enabled: bool) -> Self {
  264        Self {
  265            enabled,
  266            inlays: Vec::new(),
  267            refresh_task: Task::ready(None),
  268        }
  269    }
  270}
  271
  272#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  273pub enum InlayId {
  274    InlineCompletion(usize),
  275    Hint(usize),
  276    DebuggerValue(usize),
  277}
  278
  279impl InlayId {
  280    fn id(&self) -> usize {
  281        match self {
  282            Self::InlineCompletion(id) => *id,
  283            Self::Hint(id) => *id,
  284            Self::DebuggerValue(id) => *id,
  285        }
  286    }
  287}
  288
  289pub enum DebugCurrentRowHighlight {}
  290enum DocumentHighlightRead {}
  291enum DocumentHighlightWrite {}
  292enum InputComposition {}
  293enum SelectedTextHighlight {}
  294
  295pub enum ConflictsOuter {}
  296pub enum ConflictsOurs {}
  297pub enum ConflictsTheirs {}
  298pub enum ConflictsOursMarker {}
  299pub enum ConflictsTheirsMarker {}
  300
  301#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  302pub enum Navigated {
  303    Yes,
  304    No,
  305}
  306
  307impl Navigated {
  308    pub fn from_bool(yes: bool) -> Navigated {
  309        if yes { Navigated::Yes } else { Navigated::No }
  310    }
  311}
  312
  313#[derive(Debug, Clone, PartialEq, Eq)]
  314enum DisplayDiffHunk {
  315    Folded {
  316        display_row: DisplayRow,
  317    },
  318    Unfolded {
  319        is_created_file: bool,
  320        diff_base_byte_range: Range<usize>,
  321        display_row_range: Range<DisplayRow>,
  322        multi_buffer_range: Range<Anchor>,
  323        status: DiffHunkStatus,
  324    },
  325}
  326
  327pub enum HideMouseCursorOrigin {
  328    TypingAction,
  329    MovementAction,
  330}
  331
  332pub fn init_settings(cx: &mut App) {
  333    EditorSettings::register(cx);
  334}
  335
  336pub fn init(cx: &mut App) {
  337    init_settings(cx);
  338
  339    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  340
  341    workspace::register_project_item::<Editor>(cx);
  342    workspace::FollowableViewRegistry::register::<Editor>(cx);
  343    workspace::register_serializable_item::<Editor>(cx);
  344
  345    cx.observe_new(
  346        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  347            workspace.register_action(Editor::new_file);
  348            workspace.register_action(Editor::new_file_vertical);
  349            workspace.register_action(Editor::new_file_horizontal);
  350            workspace.register_action(Editor::cancel_language_server_work);
  351        },
  352    )
  353    .detach();
  354
  355    cx.on_action(move |_: &workspace::NewFile, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    Editor::new_file(workspace, &Default::default(), window, cx)
  364                },
  365            )
  366            .detach();
  367        }
  368    });
  369    cx.on_action(move |_: &workspace::NewWindow, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    cx.activate(true);
  378                    Editor::new_file(workspace, &Default::default(), window, cx)
  379                },
  380            )
  381            .detach();
  382        }
  383    });
  384}
  385
  386pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  387    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  388}
  389
  390pub trait DiagnosticRenderer {
  391    fn render_group(
  392        &self,
  393        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  394        buffer_id: BufferId,
  395        snapshot: EditorSnapshot,
  396        editor: WeakEntity<Editor>,
  397        cx: &mut App,
  398    ) -> Vec<BlockProperties<Anchor>>;
  399
  400    fn render_hover(
  401        &self,
  402        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  403        range: Range<Point>,
  404        buffer_id: BufferId,
  405        cx: &mut App,
  406    ) -> Option<Entity<markdown::Markdown>>;
  407
  408    fn open_link(
  409        &self,
  410        editor: &mut Editor,
  411        link: SharedString,
  412        window: &mut Window,
  413        cx: &mut Context<Editor>,
  414    );
  415}
  416
  417pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  418
  419impl GlobalDiagnosticRenderer {
  420    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  421        cx.try_global::<Self>().map(|g| g.0.clone())
  422    }
  423}
  424
  425impl gpui::Global for GlobalDiagnosticRenderer {}
  426pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  427    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  428}
  429
  430pub struct SearchWithinRange;
  431
  432trait InvalidationRegion {
  433    fn ranges(&self) -> &[Range<Anchor>];
  434}
  435
  436#[derive(Clone, Debug, PartialEq)]
  437pub enum SelectPhase {
  438    Begin {
  439        position: DisplayPoint,
  440        add: bool,
  441        click_count: usize,
  442    },
  443    BeginColumnar {
  444        position: DisplayPoint,
  445        reset: bool,
  446        goal_column: u32,
  447    },
  448    Extend {
  449        position: DisplayPoint,
  450        click_count: usize,
  451    },
  452    Update {
  453        position: DisplayPoint,
  454        goal_column: u32,
  455        scroll_delta: gpui::Point<f32>,
  456    },
  457    End,
  458}
  459
  460#[derive(Clone, Debug)]
  461pub enum SelectMode {
  462    Character,
  463    Word(Range<Anchor>),
  464    Line(Range<Anchor>),
  465    All,
  466}
  467
  468#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  469pub enum EditorMode {
  470    SingleLine {
  471        auto_width: bool,
  472    },
  473    AutoHeight {
  474        max_lines: usize,
  475    },
  476    Full {
  477        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  478        scale_ui_elements_with_buffer_font_size: bool,
  479        /// When set to `true`, the editor will render a background for the active line.
  480        show_active_line_background: bool,
  481        /// When set to `true`, the editor's height will be determined by its content.
  482        sized_by_content: bool,
  483    },
  484}
  485
  486impl EditorMode {
  487    pub fn full() -> Self {
  488        Self::Full {
  489            scale_ui_elements_with_buffer_font_size: true,
  490            show_active_line_background: true,
  491            sized_by_content: false,
  492        }
  493    }
  494
  495    pub fn is_full(&self) -> bool {
  496        matches!(self, Self::Full { .. })
  497    }
  498}
  499
  500#[derive(Copy, Clone, Debug)]
  501pub enum SoftWrap {
  502    /// Prefer not to wrap at all.
  503    ///
  504    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  505    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  506    GitDiff,
  507    /// Prefer a single line generally, unless an overly long line is encountered.
  508    None,
  509    /// Soft wrap lines that exceed the editor width.
  510    EditorWidth,
  511    /// Soft wrap lines at the preferred line length.
  512    Column(u32),
  513    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  514    Bounded(u32),
  515}
  516
  517#[derive(Clone)]
  518pub struct EditorStyle {
  519    pub background: Hsla,
  520    pub local_player: PlayerColor,
  521    pub text: TextStyle,
  522    pub scrollbar_width: Pixels,
  523    pub syntax: Arc<SyntaxTheme>,
  524    pub status: StatusColors,
  525    pub inlay_hints_style: HighlightStyle,
  526    pub inline_completion_styles: InlineCompletionStyles,
  527    pub unnecessary_code_fade: f32,
  528}
  529
  530impl Default for EditorStyle {
  531    fn default() -> Self {
  532        Self {
  533            background: Hsla::default(),
  534            local_player: PlayerColor::default(),
  535            text: TextStyle::default(),
  536            scrollbar_width: Pixels::default(),
  537            syntax: Default::default(),
  538            // HACK: Status colors don't have a real default.
  539            // We should look into removing the status colors from the editor
  540            // style and retrieve them directly from the theme.
  541            status: StatusColors::dark(),
  542            inlay_hints_style: HighlightStyle::default(),
  543            inline_completion_styles: InlineCompletionStyles {
  544                insertion: HighlightStyle::default(),
  545                whitespace: HighlightStyle::default(),
  546            },
  547            unnecessary_code_fade: Default::default(),
  548        }
  549    }
  550}
  551
  552pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  553    let show_background = language_settings::language_settings(None, None, cx)
  554        .inlay_hints
  555        .show_background;
  556
  557    HighlightStyle {
  558        color: Some(cx.theme().status().hint),
  559        background_color: show_background.then(|| cx.theme().status().hint_background),
  560        ..HighlightStyle::default()
  561    }
  562}
  563
  564pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  565    InlineCompletionStyles {
  566        insertion: HighlightStyle {
  567            color: Some(cx.theme().status().predictive),
  568            ..HighlightStyle::default()
  569        },
  570        whitespace: HighlightStyle {
  571            background_color: Some(cx.theme().status().created_background),
  572            ..HighlightStyle::default()
  573        },
  574    }
  575}
  576
  577type CompletionId = usize;
  578
  579pub(crate) enum EditDisplayMode {
  580    TabAccept,
  581    DiffPopover,
  582    Inline,
  583}
  584
  585enum InlineCompletion {
  586    Edit {
  587        edits: Vec<(Range<Anchor>, String)>,
  588        edit_preview: Option<EditPreview>,
  589        display_mode: EditDisplayMode,
  590        snapshot: BufferSnapshot,
  591    },
  592    Move {
  593        target: Anchor,
  594        snapshot: BufferSnapshot,
  595    },
  596}
  597
  598struct InlineCompletionState {
  599    inlay_ids: Vec<InlayId>,
  600    completion: InlineCompletion,
  601    completion_id: Option<SharedString>,
  602    invalidation_range: Range<Anchor>,
  603}
  604
  605enum EditPredictionSettings {
  606    Disabled,
  607    Enabled {
  608        show_in_menu: bool,
  609        preview_requires_modifier: bool,
  610    },
  611}
  612
  613enum InlineCompletionHighlight {}
  614
  615#[derive(Debug, Clone)]
  616struct InlineDiagnostic {
  617    message: SharedString,
  618    group_id: usize,
  619    is_primary: bool,
  620    start: Point,
  621    severity: DiagnosticSeverity,
  622}
  623
  624pub enum MenuInlineCompletionsPolicy {
  625    Never,
  626    ByProvider,
  627}
  628
  629pub enum EditPredictionPreview {
  630    /// Modifier is not pressed
  631    Inactive { released_too_fast: bool },
  632    /// Modifier pressed
  633    Active {
  634        since: Instant,
  635        previous_scroll_position: Option<ScrollAnchor>,
  636    },
  637}
  638
  639impl EditPredictionPreview {
  640    pub fn released_too_fast(&self) -> bool {
  641        match self {
  642            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  643            EditPredictionPreview::Active { .. } => false,
  644        }
  645    }
  646
  647    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  648        if let EditPredictionPreview::Active {
  649            previous_scroll_position,
  650            ..
  651        } = self
  652        {
  653            *previous_scroll_position = scroll_position;
  654        }
  655    }
  656}
  657
  658pub struct ContextMenuOptions {
  659    pub min_entries_visible: usize,
  660    pub max_entries_visible: usize,
  661    pub placement: Option<ContextMenuPlacement>,
  662}
  663
  664#[derive(Debug, Clone, PartialEq, Eq)]
  665pub enum ContextMenuPlacement {
  666    Above,
  667    Below,
  668}
  669
  670#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  671struct EditorActionId(usize);
  672
  673impl EditorActionId {
  674    pub fn post_inc(&mut self) -> Self {
  675        let answer = self.0;
  676
  677        *self = Self(answer + 1);
  678
  679        Self(answer)
  680    }
  681}
  682
  683// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  684// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  685
  686type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  687type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  688
  689#[derive(Default)]
  690struct ScrollbarMarkerState {
  691    scrollbar_size: Size<Pixels>,
  692    dirty: bool,
  693    markers: Arc<[PaintQuad]>,
  694    pending_refresh: Option<Task<Result<()>>>,
  695}
  696
  697impl ScrollbarMarkerState {
  698    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  699        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  700    }
  701}
  702
  703#[derive(Clone, Debug)]
  704struct RunnableTasks {
  705    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  706    offset: multi_buffer::Anchor,
  707    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  708    column: u32,
  709    // Values of all named captures, including those starting with '_'
  710    extra_variables: HashMap<String, String>,
  711    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  712    context_range: Range<BufferOffset>,
  713}
  714
  715impl RunnableTasks {
  716    fn resolve<'a>(
  717        &'a self,
  718        cx: &'a task::TaskContext,
  719    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  720        self.templates.iter().filter_map(|(kind, template)| {
  721            template
  722                .resolve_task(&kind.to_id_base(), cx)
  723                .map(|task| (kind.clone(), task))
  724        })
  725    }
  726}
  727
  728#[derive(Clone)]
  729struct ResolvedTasks {
  730    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  731    position: Anchor,
  732}
  733
  734#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  735struct BufferOffset(usize);
  736
  737// Addons allow storing per-editor state in other crates (e.g. Vim)
  738pub trait Addon: 'static {
  739    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  740
  741    fn render_buffer_header_controls(
  742        &self,
  743        _: &ExcerptInfo,
  744        _: &Window,
  745        _: &App,
  746    ) -> Option<AnyElement> {
  747        None
  748    }
  749
  750    fn to_any(&self) -> &dyn std::any::Any;
  751
  752    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  753        None
  754    }
  755}
  756
  757/// A set of caret positions, registered when the editor was edited.
  758pub struct ChangeList {
  759    changes: Vec<Vec<Anchor>>,
  760    /// Currently "selected" change.
  761    position: Option<usize>,
  762}
  763
  764impl ChangeList {
  765    pub fn new() -> Self {
  766        Self {
  767            changes: Vec::new(),
  768            position: None,
  769        }
  770    }
  771
  772    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  773    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  774    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  775        if self.changes.is_empty() {
  776            return None;
  777        }
  778
  779        let prev = self.position.unwrap_or(self.changes.len());
  780        let next = if direction == Direction::Prev {
  781            prev.saturating_sub(count)
  782        } else {
  783            (prev + count).min(self.changes.len() - 1)
  784        };
  785        self.position = Some(next);
  786        self.changes.get(next).map(|anchors| anchors.as_slice())
  787    }
  788
  789    /// Adds a new change to the list, resetting the change list position.
  790    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  791        self.position.take();
  792        if pop_state {
  793            self.changes.pop();
  794        }
  795        self.changes.push(new_positions.clone());
  796    }
  797
  798    pub fn last(&self) -> Option<&[Anchor]> {
  799        self.changes.last().map(|anchors| anchors.as_slice())
  800    }
  801}
  802
  803#[derive(Clone)]
  804struct InlineBlamePopoverState {
  805    scroll_handle: ScrollHandle,
  806    commit_message: Option<ParsedCommitMessage>,
  807    markdown: Entity<Markdown>,
  808}
  809
  810struct InlineBlamePopover {
  811    position: gpui::Point<Pixels>,
  812    show_task: Option<Task<()>>,
  813    hide_task: Option<Task<()>>,
  814    popover_bounds: Option<Bounds<Pixels>>,
  815    popover_state: InlineBlamePopoverState,
  816}
  817
  818/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  819///
  820/// See the [module level documentation](self) for more information.
  821pub struct Editor {
  822    focus_handle: FocusHandle,
  823    last_focused_descendant: Option<WeakFocusHandle>,
  824    /// The text buffer being edited
  825    buffer: Entity<MultiBuffer>,
  826    /// Map of how text in the buffer should be displayed.
  827    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  828    pub display_map: Entity<DisplayMap>,
  829    pub selections: SelectionsCollection,
  830    pub scroll_manager: ScrollManager,
  831    /// When inline assist editors are linked, they all render cursors because
  832    /// typing enters text into each of them, even the ones that aren't focused.
  833    pub(crate) show_cursor_when_unfocused: bool,
  834    columnar_selection_tail: Option<Anchor>,
  835    add_selections_state: Option<AddSelectionsState>,
  836    select_next_state: Option<SelectNextState>,
  837    select_prev_state: Option<SelectNextState>,
  838    selection_history: SelectionHistory,
  839    autoclose_regions: Vec<AutocloseRegion>,
  840    snippet_stack: InvalidationStack<SnippetState>,
  841    select_syntax_node_history: SelectSyntaxNodeHistory,
  842    ime_transaction: Option<TransactionId>,
  843    active_diagnostics: ActiveDiagnostic,
  844    show_inline_diagnostics: bool,
  845    inline_diagnostics_update: Task<()>,
  846    inline_diagnostics_enabled: bool,
  847    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  848    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  849    hard_wrap: Option<usize>,
  850
  851    // TODO: make this a access method
  852    pub project: Option<Entity<Project>>,
  853    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  854    completion_provider: Option<Box<dyn CompletionProvider>>,
  855    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  856    blink_manager: Entity<BlinkManager>,
  857    show_cursor_names: bool,
  858    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  859    pub show_local_selections: bool,
  860    mode: EditorMode,
  861    show_breadcrumbs: bool,
  862    show_gutter: bool,
  863    show_scrollbars: bool,
  864    disable_scrolling: bool,
  865    disable_expand_excerpt_buttons: bool,
  866    show_line_numbers: Option<bool>,
  867    use_relative_line_numbers: Option<bool>,
  868    show_git_diff_gutter: Option<bool>,
  869    show_code_actions: Option<bool>,
  870    show_runnables: Option<bool>,
  871    show_breakpoints: Option<bool>,
  872    show_wrap_guides: Option<bool>,
  873    show_indent_guides: Option<bool>,
  874    placeholder_text: Option<Arc<str>>,
  875    highlight_order: usize,
  876    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  877    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  878    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  879    scrollbar_marker_state: ScrollbarMarkerState,
  880    active_indent_guides_state: ActiveIndentGuidesState,
  881    nav_history: Option<ItemNavHistory>,
  882    context_menu: RefCell<Option<CodeContextMenu>>,
  883    context_menu_options: Option<ContextMenuOptions>,
  884    mouse_context_menu: Option<MouseContextMenu>,
  885    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  886    inline_blame_popover: Option<InlineBlamePopover>,
  887    signature_help_state: SignatureHelpState,
  888    auto_signature_help: Option<bool>,
  889    find_all_references_task_sources: Vec<Anchor>,
  890    next_completion_id: CompletionId,
  891    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  892    code_actions_task: Option<Task<Result<()>>>,
  893    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  894    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  895    document_highlights_task: Option<Task<()>>,
  896    linked_editing_range_task: Option<Task<Option<()>>>,
  897    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  898    pending_rename: Option<RenameState>,
  899    searchable: bool,
  900    cursor_shape: CursorShape,
  901    current_line_highlight: Option<CurrentLineHighlight>,
  902    collapse_matches: bool,
  903    autoindent_mode: Option<AutoindentMode>,
  904    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  905    input_enabled: bool,
  906    use_modal_editing: bool,
  907    read_only: bool,
  908    leader_peer_id: Option<PeerId>,
  909    remote_id: Option<ViewId>,
  910    pub hover_state: HoverState,
  911    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  912    gutter_hovered: bool,
  913    hovered_link_state: Option<HoveredLinkState>,
  914    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  915    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  916    active_inline_completion: Option<InlineCompletionState>,
  917    /// Used to prevent flickering as the user types while the menu is open
  918    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  919    edit_prediction_settings: EditPredictionSettings,
  920    inline_completions_hidden_for_vim_mode: bool,
  921    show_inline_completions_override: Option<bool>,
  922    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  923    edit_prediction_preview: EditPredictionPreview,
  924    edit_prediction_indent_conflict: bool,
  925    edit_prediction_requires_modifier_in_indent_conflict: bool,
  926    inlay_hint_cache: InlayHintCache,
  927    next_inlay_id: usize,
  928    _subscriptions: Vec<Subscription>,
  929    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  930    gutter_dimensions: GutterDimensions,
  931    style: Option<EditorStyle>,
  932    text_style_refinement: Option<TextStyleRefinement>,
  933    next_editor_action_id: EditorActionId,
  934    editor_actions:
  935        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  936    use_autoclose: bool,
  937    use_auto_surround: bool,
  938    auto_replace_emoji_shortcode: bool,
  939    jsx_tag_auto_close_enabled_in_any_buffer: bool,
  940    show_git_blame_gutter: bool,
  941    show_git_blame_inline: bool,
  942    show_git_blame_inline_delay_task: Option<Task<()>>,
  943    git_blame_inline_enabled: bool,
  944    render_diff_hunk_controls: RenderDiffHunkControlsFn,
  945    serialize_dirty_buffers: bool,
  946    show_selection_menu: Option<bool>,
  947    blame: Option<Entity<GitBlame>>,
  948    blame_subscription: Option<Subscription>,
  949    custom_context_menu: Option<
  950        Box<
  951            dyn 'static
  952                + Fn(
  953                    &mut Self,
  954                    DisplayPoint,
  955                    &mut Window,
  956                    &mut Context<Self>,
  957                ) -> Option<Entity<ui::ContextMenu>>,
  958        >,
  959    >,
  960    last_bounds: Option<Bounds<Pixels>>,
  961    last_position_map: Option<Rc<PositionMap>>,
  962    expect_bounds_change: Option<Bounds<Pixels>>,
  963    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  964    tasks_update_task: Option<Task<()>>,
  965    breakpoint_store: Option<Entity<BreakpointStore>>,
  966    /// Allow's a user to create a breakpoint by selecting this indicator
  967    /// It should be None while a user is not hovering over the gutter
  968    /// Otherwise it represents the point that the breakpoint will be shown
  969    gutter_breakpoint_indicator: (Option<(DisplayPoint, bool)>, Option<Task<()>>),
  970    in_project_search: bool,
  971    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
  972    breadcrumb_header: Option<String>,
  973    focused_block: Option<FocusedBlock>,
  974    next_scroll_position: NextScrollCursorCenterTopBottom,
  975    addons: HashMap<TypeId, Box<dyn Addon>>,
  976    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
  977    load_diff_task: Option<Shared<Task<()>>>,
  978    selection_mark_mode: bool,
  979    toggle_fold_multiple_buffers: Task<()>,
  980    _scroll_cursor_center_top_bottom_task: Task<()>,
  981    serialize_selections: Task<()>,
  982    serialize_folds: Task<()>,
  983    mouse_cursor_hidden: bool,
  984    hide_mouse_mode: HideMouseMode,
  985    pub change_list: ChangeList,
  986    inline_value_cache: InlineValueCache,
  987}
  988
  989#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
  990enum NextScrollCursorCenterTopBottom {
  991    #[default]
  992    Center,
  993    Top,
  994    Bottom,
  995}
  996
  997impl NextScrollCursorCenterTopBottom {
  998    fn next(&self) -> Self {
  999        match self {
 1000            Self::Center => Self::Top,
 1001            Self::Top => Self::Bottom,
 1002            Self::Bottom => Self::Center,
 1003        }
 1004    }
 1005}
 1006
 1007#[derive(Clone)]
 1008pub struct EditorSnapshot {
 1009    pub mode: EditorMode,
 1010    show_gutter: bool,
 1011    show_line_numbers: Option<bool>,
 1012    show_git_diff_gutter: Option<bool>,
 1013    show_code_actions: Option<bool>,
 1014    show_runnables: Option<bool>,
 1015    show_breakpoints: Option<bool>,
 1016    git_blame_gutter_max_author_length: Option<usize>,
 1017    pub display_snapshot: DisplaySnapshot,
 1018    pub placeholder_text: Option<Arc<str>>,
 1019    is_focused: bool,
 1020    scroll_anchor: ScrollAnchor,
 1021    ongoing_scroll: OngoingScroll,
 1022    current_line_highlight: CurrentLineHighlight,
 1023    gutter_hovered: bool,
 1024}
 1025
 1026#[derive(Default, Debug, Clone, Copy)]
 1027pub struct GutterDimensions {
 1028    pub left_padding: Pixels,
 1029    pub right_padding: Pixels,
 1030    pub width: Pixels,
 1031    pub margin: Pixels,
 1032    pub git_blame_entries_width: Option<Pixels>,
 1033}
 1034
 1035impl GutterDimensions {
 1036    /// The full width of the space taken up by the gutter.
 1037    pub fn full_width(&self) -> Pixels {
 1038        self.margin + self.width
 1039    }
 1040
 1041    /// The width of the space reserved for the fold indicators,
 1042    /// use alongside 'justify_end' and `gutter_width` to
 1043    /// right align content with the line numbers
 1044    pub fn fold_area_width(&self) -> Pixels {
 1045        self.margin + self.right_padding
 1046    }
 1047}
 1048
 1049#[derive(Debug)]
 1050pub struct RemoteSelection {
 1051    pub replica_id: ReplicaId,
 1052    pub selection: Selection<Anchor>,
 1053    pub cursor_shape: CursorShape,
 1054    pub peer_id: PeerId,
 1055    pub line_mode: bool,
 1056    pub participant_index: Option<ParticipantIndex>,
 1057    pub user_name: Option<SharedString>,
 1058}
 1059
 1060#[derive(Clone, Debug)]
 1061struct SelectionHistoryEntry {
 1062    selections: Arc<[Selection<Anchor>]>,
 1063    select_next_state: Option<SelectNextState>,
 1064    select_prev_state: Option<SelectNextState>,
 1065    add_selections_state: Option<AddSelectionsState>,
 1066}
 1067
 1068enum SelectionHistoryMode {
 1069    Normal,
 1070    Undoing,
 1071    Redoing,
 1072}
 1073
 1074#[derive(Clone, PartialEq, Eq, Hash)]
 1075struct HoveredCursor {
 1076    replica_id: u16,
 1077    selection_id: usize,
 1078}
 1079
 1080impl Default for SelectionHistoryMode {
 1081    fn default() -> Self {
 1082        Self::Normal
 1083    }
 1084}
 1085
 1086#[derive(Default)]
 1087struct SelectionHistory {
 1088    #[allow(clippy::type_complexity)]
 1089    selections_by_transaction:
 1090        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1091    mode: SelectionHistoryMode,
 1092    undo_stack: VecDeque<SelectionHistoryEntry>,
 1093    redo_stack: VecDeque<SelectionHistoryEntry>,
 1094}
 1095
 1096impl SelectionHistory {
 1097    fn insert_transaction(
 1098        &mut self,
 1099        transaction_id: TransactionId,
 1100        selections: Arc<[Selection<Anchor>]>,
 1101    ) {
 1102        self.selections_by_transaction
 1103            .insert(transaction_id, (selections, None));
 1104    }
 1105
 1106    #[allow(clippy::type_complexity)]
 1107    fn transaction(
 1108        &self,
 1109        transaction_id: TransactionId,
 1110    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1111        self.selections_by_transaction.get(&transaction_id)
 1112    }
 1113
 1114    #[allow(clippy::type_complexity)]
 1115    fn transaction_mut(
 1116        &mut self,
 1117        transaction_id: TransactionId,
 1118    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1119        self.selections_by_transaction.get_mut(&transaction_id)
 1120    }
 1121
 1122    fn push(&mut self, entry: SelectionHistoryEntry) {
 1123        if !entry.selections.is_empty() {
 1124            match self.mode {
 1125                SelectionHistoryMode::Normal => {
 1126                    self.push_undo(entry);
 1127                    self.redo_stack.clear();
 1128                }
 1129                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1130                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1131            }
 1132        }
 1133    }
 1134
 1135    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1136        if self
 1137            .undo_stack
 1138            .back()
 1139            .map_or(true, |e| e.selections != entry.selections)
 1140        {
 1141            self.undo_stack.push_back(entry);
 1142            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1143                self.undo_stack.pop_front();
 1144            }
 1145        }
 1146    }
 1147
 1148    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1149        if self
 1150            .redo_stack
 1151            .back()
 1152            .map_or(true, |e| e.selections != entry.selections)
 1153        {
 1154            self.redo_stack.push_back(entry);
 1155            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1156                self.redo_stack.pop_front();
 1157            }
 1158        }
 1159    }
 1160}
 1161
 1162#[derive(Clone, Copy)]
 1163pub struct RowHighlightOptions {
 1164    pub autoscroll: bool,
 1165    pub include_gutter: bool,
 1166}
 1167
 1168impl Default for RowHighlightOptions {
 1169    fn default() -> Self {
 1170        Self {
 1171            autoscroll: Default::default(),
 1172            include_gutter: true,
 1173        }
 1174    }
 1175}
 1176
 1177struct RowHighlight {
 1178    index: usize,
 1179    range: Range<Anchor>,
 1180    color: Hsla,
 1181    options: RowHighlightOptions,
 1182    type_id: TypeId,
 1183}
 1184
 1185#[derive(Clone, Debug)]
 1186struct AddSelectionsState {
 1187    above: bool,
 1188    stack: Vec<usize>,
 1189}
 1190
 1191#[derive(Clone)]
 1192struct SelectNextState {
 1193    query: AhoCorasick,
 1194    wordwise: bool,
 1195    done: bool,
 1196}
 1197
 1198impl std::fmt::Debug for SelectNextState {
 1199    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1200        f.debug_struct(std::any::type_name::<Self>())
 1201            .field("wordwise", &self.wordwise)
 1202            .field("done", &self.done)
 1203            .finish()
 1204    }
 1205}
 1206
 1207#[derive(Debug)]
 1208struct AutocloseRegion {
 1209    selection_id: usize,
 1210    range: Range<Anchor>,
 1211    pair: BracketPair,
 1212}
 1213
 1214#[derive(Debug)]
 1215struct SnippetState {
 1216    ranges: Vec<Vec<Range<Anchor>>>,
 1217    active_index: usize,
 1218    choices: Vec<Option<Vec<String>>>,
 1219}
 1220
 1221#[doc(hidden)]
 1222pub struct RenameState {
 1223    pub range: Range<Anchor>,
 1224    pub old_name: Arc<str>,
 1225    pub editor: Entity<Editor>,
 1226    block_id: CustomBlockId,
 1227}
 1228
 1229struct InvalidationStack<T>(Vec<T>);
 1230
 1231struct RegisteredInlineCompletionProvider {
 1232    provider: Arc<dyn InlineCompletionProviderHandle>,
 1233    _subscription: Subscription,
 1234}
 1235
 1236#[derive(Debug, PartialEq, Eq)]
 1237pub struct ActiveDiagnosticGroup {
 1238    pub active_range: Range<Anchor>,
 1239    pub active_message: String,
 1240    pub group_id: usize,
 1241    pub blocks: HashSet<CustomBlockId>,
 1242}
 1243
 1244#[derive(Debug, PartialEq, Eq)]
 1245#[allow(clippy::large_enum_variant)]
 1246pub(crate) enum ActiveDiagnostic {
 1247    None,
 1248    All,
 1249    Group(ActiveDiagnosticGroup),
 1250}
 1251
 1252#[derive(Serialize, Deserialize, Clone, Debug)]
 1253pub struct ClipboardSelection {
 1254    /// The number of bytes in this selection.
 1255    pub len: usize,
 1256    /// Whether this was a full-line selection.
 1257    pub is_entire_line: bool,
 1258    /// The indentation of the first line when this content was originally copied.
 1259    pub first_line_indent: u32,
 1260}
 1261
 1262// selections, scroll behavior, was newest selection reversed
 1263type SelectSyntaxNodeHistoryState = (
 1264    Box<[Selection<usize>]>,
 1265    SelectSyntaxNodeScrollBehavior,
 1266    bool,
 1267);
 1268
 1269#[derive(Default)]
 1270struct SelectSyntaxNodeHistory {
 1271    stack: Vec<SelectSyntaxNodeHistoryState>,
 1272    // disable temporarily to allow changing selections without losing the stack
 1273    pub disable_clearing: bool,
 1274}
 1275
 1276impl SelectSyntaxNodeHistory {
 1277    pub fn try_clear(&mut self) {
 1278        if !self.disable_clearing {
 1279            self.stack.clear();
 1280        }
 1281    }
 1282
 1283    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1284        self.stack.push(selection);
 1285    }
 1286
 1287    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1288        self.stack.pop()
 1289    }
 1290}
 1291
 1292enum SelectSyntaxNodeScrollBehavior {
 1293    CursorTop,
 1294    FitSelection,
 1295    CursorBottom,
 1296}
 1297
 1298#[derive(Debug)]
 1299pub(crate) struct NavigationData {
 1300    cursor_anchor: Anchor,
 1301    cursor_position: Point,
 1302    scroll_anchor: ScrollAnchor,
 1303    scroll_top_row: u32,
 1304}
 1305
 1306#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1307pub enum GotoDefinitionKind {
 1308    Symbol,
 1309    Declaration,
 1310    Type,
 1311    Implementation,
 1312}
 1313
 1314#[derive(Debug, Clone)]
 1315enum InlayHintRefreshReason {
 1316    ModifiersChanged(bool),
 1317    Toggle(bool),
 1318    SettingsChange(InlayHintSettings),
 1319    NewLinesShown,
 1320    BufferEdited(HashSet<Arc<Language>>),
 1321    RefreshRequested,
 1322    ExcerptsRemoved(Vec<ExcerptId>),
 1323}
 1324
 1325impl InlayHintRefreshReason {
 1326    fn description(&self) -> &'static str {
 1327        match self {
 1328            Self::ModifiersChanged(_) => "modifiers changed",
 1329            Self::Toggle(_) => "toggle",
 1330            Self::SettingsChange(_) => "settings change",
 1331            Self::NewLinesShown => "new lines shown",
 1332            Self::BufferEdited(_) => "buffer edited",
 1333            Self::RefreshRequested => "refresh requested",
 1334            Self::ExcerptsRemoved(_) => "excerpts removed",
 1335        }
 1336    }
 1337}
 1338
 1339pub enum FormatTarget {
 1340    Buffers,
 1341    Ranges(Vec<Range<MultiBufferPoint>>),
 1342}
 1343
 1344pub(crate) struct FocusedBlock {
 1345    id: BlockId,
 1346    focus_handle: WeakFocusHandle,
 1347}
 1348
 1349#[derive(Clone)]
 1350enum JumpData {
 1351    MultiBufferRow {
 1352        row: MultiBufferRow,
 1353        line_offset_from_top: u32,
 1354    },
 1355    MultiBufferPoint {
 1356        excerpt_id: ExcerptId,
 1357        position: Point,
 1358        anchor: text::Anchor,
 1359        line_offset_from_top: u32,
 1360    },
 1361}
 1362
 1363pub enum MultibufferSelectionMode {
 1364    First,
 1365    All,
 1366}
 1367
 1368#[derive(Clone, Copy, Debug, Default)]
 1369pub struct RewrapOptions {
 1370    pub override_language_settings: bool,
 1371    pub preserve_existing_whitespace: bool,
 1372}
 1373
 1374impl Editor {
 1375    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1376        let buffer = cx.new(|cx| Buffer::local("", cx));
 1377        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1378        Self::new(
 1379            EditorMode::SingleLine { auto_width: false },
 1380            buffer,
 1381            None,
 1382            window,
 1383            cx,
 1384        )
 1385    }
 1386
 1387    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1388        let buffer = cx.new(|cx| Buffer::local("", cx));
 1389        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1390        Self::new(EditorMode::full(), buffer, None, window, cx)
 1391    }
 1392
 1393    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1394        let buffer = cx.new(|cx| Buffer::local("", cx));
 1395        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1396        Self::new(
 1397            EditorMode::SingleLine { auto_width: true },
 1398            buffer,
 1399            None,
 1400            window,
 1401            cx,
 1402        )
 1403    }
 1404
 1405    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1406        let buffer = cx.new(|cx| Buffer::local("", cx));
 1407        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1408        Self::new(
 1409            EditorMode::AutoHeight { max_lines },
 1410            buffer,
 1411            None,
 1412            window,
 1413            cx,
 1414        )
 1415    }
 1416
 1417    pub fn for_buffer(
 1418        buffer: Entity<Buffer>,
 1419        project: Option<Entity<Project>>,
 1420        window: &mut Window,
 1421        cx: &mut Context<Self>,
 1422    ) -> Self {
 1423        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1424        Self::new(EditorMode::full(), buffer, project, window, cx)
 1425    }
 1426
 1427    pub fn for_multibuffer(
 1428        buffer: Entity<MultiBuffer>,
 1429        project: Option<Entity<Project>>,
 1430        window: &mut Window,
 1431        cx: &mut Context<Self>,
 1432    ) -> Self {
 1433        Self::new(EditorMode::full(), buffer, project, window, cx)
 1434    }
 1435
 1436    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1437        let mut clone = Self::new(
 1438            self.mode,
 1439            self.buffer.clone(),
 1440            self.project.clone(),
 1441            window,
 1442            cx,
 1443        );
 1444        self.display_map.update(cx, |display_map, cx| {
 1445            let snapshot = display_map.snapshot(cx);
 1446            clone.display_map.update(cx, |display_map, cx| {
 1447                display_map.set_state(&snapshot, cx);
 1448            });
 1449        });
 1450        clone.folds_did_change(cx);
 1451        clone.selections.clone_state(&self.selections);
 1452        clone.scroll_manager.clone_state(&self.scroll_manager);
 1453        clone.searchable = self.searchable;
 1454        clone.read_only = self.read_only;
 1455        clone
 1456    }
 1457
 1458    pub fn new(
 1459        mode: EditorMode,
 1460        buffer: Entity<MultiBuffer>,
 1461        project: Option<Entity<Project>>,
 1462        window: &mut Window,
 1463        cx: &mut Context<Self>,
 1464    ) -> Self {
 1465        let style = window.text_style();
 1466        let font_size = style.font_size.to_pixels(window.rem_size());
 1467        let editor = cx.entity().downgrade();
 1468        let fold_placeholder = FoldPlaceholder {
 1469            constrain_width: true,
 1470            render: Arc::new(move |fold_id, fold_range, cx| {
 1471                let editor = editor.clone();
 1472                div()
 1473                    .id(fold_id)
 1474                    .bg(cx.theme().colors().ghost_element_background)
 1475                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1476                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1477                    .rounded_xs()
 1478                    .size_full()
 1479                    .cursor_pointer()
 1480                    .child("")
 1481                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1482                    .on_click(move |_, _window, cx| {
 1483                        editor
 1484                            .update(cx, |editor, cx| {
 1485                                editor.unfold_ranges(
 1486                                    &[fold_range.start..fold_range.end],
 1487                                    true,
 1488                                    false,
 1489                                    cx,
 1490                                );
 1491                                cx.stop_propagation();
 1492                            })
 1493                            .ok();
 1494                    })
 1495                    .into_any()
 1496            }),
 1497            merge_adjacent: true,
 1498            ..Default::default()
 1499        };
 1500        let display_map = cx.new(|cx| {
 1501            DisplayMap::new(
 1502                buffer.clone(),
 1503                style.font(),
 1504                font_size,
 1505                None,
 1506                FILE_HEADER_HEIGHT,
 1507                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1508                fold_placeholder,
 1509                cx,
 1510            )
 1511        });
 1512
 1513        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1514
 1515        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1516
 1517        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1518            .then(|| language_settings::SoftWrap::None);
 1519
 1520        let mut project_subscriptions = Vec::new();
 1521        if mode.is_full() {
 1522            if let Some(project) = project.as_ref() {
 1523                project_subscriptions.push(cx.subscribe_in(
 1524                    project,
 1525                    window,
 1526                    |editor, _, event, window, cx| match event {
 1527                        project::Event::RefreshCodeLens => {
 1528                            // we always query lens with actions, without storing them, always refreshing them
 1529                        }
 1530                        project::Event::RefreshInlayHints => {
 1531                            editor
 1532                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1533                        }
 1534                        project::Event::SnippetEdit(id, snippet_edits) => {
 1535                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1536                                let focus_handle = editor.focus_handle(cx);
 1537                                if focus_handle.is_focused(window) {
 1538                                    let snapshot = buffer.read(cx).snapshot();
 1539                                    for (range, snippet) in snippet_edits {
 1540                                        let editor_range =
 1541                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1542                                        editor
 1543                                            .insert_snippet(
 1544                                                &[editor_range],
 1545                                                snippet.clone(),
 1546                                                window,
 1547                                                cx,
 1548                                            )
 1549                                            .ok();
 1550                                    }
 1551                                }
 1552                            }
 1553                        }
 1554                        _ => {}
 1555                    },
 1556                ));
 1557                if let Some(task_inventory) = project
 1558                    .read(cx)
 1559                    .task_store()
 1560                    .read(cx)
 1561                    .task_inventory()
 1562                    .cloned()
 1563                {
 1564                    project_subscriptions.push(cx.observe_in(
 1565                        &task_inventory,
 1566                        window,
 1567                        |editor, _, window, cx| {
 1568                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1569                        },
 1570                    ));
 1571                };
 1572
 1573                project_subscriptions.push(cx.subscribe_in(
 1574                    &project.read(cx).breakpoint_store(),
 1575                    window,
 1576                    |editor, _, event, window, cx| match event {
 1577                        BreakpointStoreEvent::ActiveDebugLineChanged => {
 1578                            if editor.go_to_active_debug_line(window, cx) {
 1579                                cx.stop_propagation();
 1580                            }
 1581
 1582                            editor.refresh_inline_values(cx);
 1583                        }
 1584                        _ => {}
 1585                    },
 1586                ));
 1587            }
 1588        }
 1589
 1590        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1591
 1592        let inlay_hint_settings =
 1593            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1594        let focus_handle = cx.focus_handle();
 1595        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1596            .detach();
 1597        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1598            .detach();
 1599        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1600            .detach();
 1601        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1602            .detach();
 1603
 1604        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1605            Some(false)
 1606        } else {
 1607            None
 1608        };
 1609
 1610        let breakpoint_store = match (mode, project.as_ref()) {
 1611            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1612            _ => None,
 1613        };
 1614
 1615        let mut code_action_providers = Vec::new();
 1616        let mut load_uncommitted_diff = None;
 1617        if let Some(project) = project.clone() {
 1618            load_uncommitted_diff = Some(
 1619                get_uncommitted_diff_for_buffer(
 1620                    &project,
 1621                    buffer.read(cx).all_buffers(),
 1622                    buffer.clone(),
 1623                    cx,
 1624                )
 1625                .shared(),
 1626            );
 1627            code_action_providers.push(Rc::new(project) as Rc<_>);
 1628        }
 1629
 1630        let mut this = Self {
 1631            focus_handle,
 1632            show_cursor_when_unfocused: false,
 1633            last_focused_descendant: None,
 1634            buffer: buffer.clone(),
 1635            display_map: display_map.clone(),
 1636            selections,
 1637            scroll_manager: ScrollManager::new(cx),
 1638            columnar_selection_tail: None,
 1639            add_selections_state: None,
 1640            select_next_state: None,
 1641            select_prev_state: None,
 1642            selection_history: Default::default(),
 1643            autoclose_regions: Default::default(),
 1644            snippet_stack: Default::default(),
 1645            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1646            ime_transaction: Default::default(),
 1647            active_diagnostics: ActiveDiagnostic::None,
 1648            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1649            inline_diagnostics_update: Task::ready(()),
 1650            inline_diagnostics: Vec::new(),
 1651            soft_wrap_mode_override,
 1652            hard_wrap: None,
 1653            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1654            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1655            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1656            project,
 1657            blink_manager: blink_manager.clone(),
 1658            show_local_selections: true,
 1659            show_scrollbars: true,
 1660            disable_scrolling: false,
 1661            mode,
 1662            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1663            show_gutter: mode.is_full(),
 1664            show_line_numbers: None,
 1665            use_relative_line_numbers: None,
 1666            disable_expand_excerpt_buttons: false,
 1667            show_git_diff_gutter: None,
 1668            show_code_actions: None,
 1669            show_runnables: None,
 1670            show_breakpoints: None,
 1671            show_wrap_guides: None,
 1672            show_indent_guides,
 1673            placeholder_text: None,
 1674            highlight_order: 0,
 1675            highlighted_rows: HashMap::default(),
 1676            background_highlights: Default::default(),
 1677            gutter_highlights: TreeMap::default(),
 1678            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1679            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1680            nav_history: None,
 1681            context_menu: RefCell::new(None),
 1682            context_menu_options: None,
 1683            mouse_context_menu: None,
 1684            completion_tasks: Default::default(),
 1685            inline_blame_popover: Default::default(),
 1686            signature_help_state: SignatureHelpState::default(),
 1687            auto_signature_help: None,
 1688            find_all_references_task_sources: Vec::new(),
 1689            next_completion_id: 0,
 1690            next_inlay_id: 0,
 1691            code_action_providers,
 1692            available_code_actions: Default::default(),
 1693            code_actions_task: Default::default(),
 1694            quick_selection_highlight_task: Default::default(),
 1695            debounced_selection_highlight_task: Default::default(),
 1696            document_highlights_task: Default::default(),
 1697            linked_editing_range_task: Default::default(),
 1698            pending_rename: Default::default(),
 1699            searchable: true,
 1700            cursor_shape: EditorSettings::get_global(cx)
 1701                .cursor_shape
 1702                .unwrap_or_default(),
 1703            current_line_highlight: None,
 1704            autoindent_mode: Some(AutoindentMode::EachLine),
 1705            collapse_matches: false,
 1706            workspace: None,
 1707            input_enabled: true,
 1708            use_modal_editing: mode.is_full(),
 1709            read_only: false,
 1710            use_autoclose: true,
 1711            use_auto_surround: true,
 1712            auto_replace_emoji_shortcode: false,
 1713            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1714            leader_peer_id: None,
 1715            remote_id: None,
 1716            hover_state: Default::default(),
 1717            pending_mouse_down: None,
 1718            hovered_link_state: Default::default(),
 1719            edit_prediction_provider: None,
 1720            active_inline_completion: None,
 1721            stale_inline_completion_in_menu: None,
 1722            edit_prediction_preview: EditPredictionPreview::Inactive {
 1723                released_too_fast: false,
 1724            },
 1725            inline_diagnostics_enabled: mode.is_full(),
 1726            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1727            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1728
 1729            gutter_hovered: false,
 1730            pixel_position_of_newest_cursor: None,
 1731            last_bounds: None,
 1732            last_position_map: None,
 1733            expect_bounds_change: None,
 1734            gutter_dimensions: GutterDimensions::default(),
 1735            style: None,
 1736            show_cursor_names: false,
 1737            hovered_cursors: Default::default(),
 1738            next_editor_action_id: EditorActionId::default(),
 1739            editor_actions: Rc::default(),
 1740            inline_completions_hidden_for_vim_mode: false,
 1741            show_inline_completions_override: None,
 1742            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1743            edit_prediction_settings: EditPredictionSettings::Disabled,
 1744            edit_prediction_indent_conflict: false,
 1745            edit_prediction_requires_modifier_in_indent_conflict: true,
 1746            custom_context_menu: None,
 1747            show_git_blame_gutter: false,
 1748            show_git_blame_inline: false,
 1749            show_selection_menu: None,
 1750            show_git_blame_inline_delay_task: None,
 1751            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1752            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1753            serialize_dirty_buffers: ProjectSettings::get_global(cx)
 1754                .session
 1755                .restore_unsaved_buffers,
 1756            blame: None,
 1757            blame_subscription: None,
 1758            tasks: Default::default(),
 1759
 1760            breakpoint_store,
 1761            gutter_breakpoint_indicator: (None, None),
 1762            _subscriptions: vec![
 1763                cx.observe(&buffer, Self::on_buffer_changed),
 1764                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1765                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1766                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1767                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1768                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1769                cx.observe_window_activation(window, |editor, window, cx| {
 1770                    let active = window.is_window_active();
 1771                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1772                        if active {
 1773                            blink_manager.enable(cx);
 1774                        } else {
 1775                            blink_manager.disable(cx);
 1776                        }
 1777                    });
 1778                }),
 1779            ],
 1780            tasks_update_task: None,
 1781            linked_edit_ranges: Default::default(),
 1782            in_project_search: false,
 1783            previous_search_ranges: None,
 1784            breadcrumb_header: None,
 1785            focused_block: None,
 1786            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1787            addons: HashMap::default(),
 1788            registered_buffers: HashMap::default(),
 1789            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1790            selection_mark_mode: false,
 1791            toggle_fold_multiple_buffers: Task::ready(()),
 1792            serialize_selections: Task::ready(()),
 1793            serialize_folds: Task::ready(()),
 1794            text_style_refinement: None,
 1795            load_diff_task: load_uncommitted_diff,
 1796            mouse_cursor_hidden: false,
 1797            hide_mouse_mode: EditorSettings::get_global(cx)
 1798                .hide_mouse
 1799                .unwrap_or_default(),
 1800            change_list: ChangeList::new(),
 1801        };
 1802        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1803            this._subscriptions
 1804                .push(cx.observe(breakpoints, |_, _, cx| {
 1805                    cx.notify();
 1806                }));
 1807        }
 1808        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1809        this._subscriptions.extend(project_subscriptions);
 1810
 1811        this._subscriptions.push(cx.subscribe_in(
 1812            &cx.entity(),
 1813            window,
 1814            |editor, _, e: &EditorEvent, window, cx| match e {
 1815                EditorEvent::ScrollPositionChanged { local, .. } => {
 1816                    if *local {
 1817                        let new_anchor = editor.scroll_manager.anchor();
 1818                        let snapshot = editor.snapshot(window, cx);
 1819                        editor.update_restoration_data(cx, move |data| {
 1820                            data.scroll_position = (
 1821                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1822                                new_anchor.offset,
 1823                            );
 1824                        });
 1825                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1826                        editor.inline_blame_popover.take();
 1827                    }
 1828                }
 1829                EditorEvent::Edited { .. } => {
 1830                    if !vim_enabled(cx) {
 1831                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1832                        let pop_state = editor
 1833                            .change_list
 1834                            .last()
 1835                            .map(|previous| {
 1836                                previous.len() == selections.len()
 1837                                    && previous.iter().enumerate().all(|(ix, p)| {
 1838                                        p.to_display_point(&map).row()
 1839                                            == selections[ix].head().row()
 1840                                    })
 1841                            })
 1842                            .unwrap_or(false);
 1843                        let new_positions = selections
 1844                            .into_iter()
 1845                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1846                            .collect();
 1847                        editor
 1848                            .change_list
 1849                            .push_to_change_list(pop_state, new_positions);
 1850                    }
 1851                }
 1852                _ => (),
 1853            },
 1854        ));
 1855
 1856        if let Some(dap_store) = this
 1857            .project
 1858            .as_ref()
 1859            .map(|project| project.read(cx).dap_store())
 1860        {
 1861            let weak_editor = cx.weak_entity();
 1862
 1863            this._subscriptions
 1864                .push(
 1865                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1866                        let session_entity = cx.entity();
 1867                        weak_editor
 1868                            .update(cx, |editor, cx| {
 1869                                editor._subscriptions.push(
 1870                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1871                                );
 1872                            })
 1873                            .ok();
 1874                    }),
 1875                );
 1876
 1877            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1878                this._subscriptions
 1879                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1880            }
 1881        }
 1882
 1883        this.end_selection(window, cx);
 1884        this.scroll_manager.show_scrollbars(window, cx);
 1885        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1886
 1887        if mode.is_full() {
 1888            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1889            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1890
 1891            if this.git_blame_inline_enabled {
 1892                this.git_blame_inline_enabled = true;
 1893                this.start_git_blame_inline(false, window, cx);
 1894            }
 1895
 1896            this.go_to_active_debug_line(window, cx);
 1897
 1898            if let Some(buffer) = buffer.read(cx).as_singleton() {
 1899                if let Some(project) = this.project.as_ref() {
 1900                    let handle = project.update(cx, |project, cx| {
 1901                        project.register_buffer_with_language_servers(&buffer, cx)
 1902                    });
 1903                    this.registered_buffers
 1904                        .insert(buffer.read(cx).remote_id(), handle);
 1905                }
 1906            }
 1907        }
 1908
 1909        this.report_editor_event("Editor Opened", None, cx);
 1910        this
 1911    }
 1912
 1913    pub fn deploy_mouse_context_menu(
 1914        &mut self,
 1915        position: gpui::Point<Pixels>,
 1916        context_menu: Entity<ContextMenu>,
 1917        window: &mut Window,
 1918        cx: &mut Context<Self>,
 1919    ) {
 1920        self.mouse_context_menu = Some(MouseContextMenu::new(
 1921            self,
 1922            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 1923            context_menu,
 1924            window,
 1925            cx,
 1926        ));
 1927    }
 1928
 1929    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 1930        self.mouse_context_menu
 1931            .as_ref()
 1932            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 1933    }
 1934
 1935    fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 1936        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 1937    }
 1938
 1939    fn key_context_internal(
 1940        &self,
 1941        has_active_edit_prediction: bool,
 1942        window: &Window,
 1943        cx: &App,
 1944    ) -> KeyContext {
 1945        let mut key_context = KeyContext::new_with_defaults();
 1946        key_context.add("Editor");
 1947        let mode = match self.mode {
 1948            EditorMode::SingleLine { .. } => "single_line",
 1949            EditorMode::AutoHeight { .. } => "auto_height",
 1950            EditorMode::Full { .. } => "full",
 1951        };
 1952
 1953        if EditorSettings::jupyter_enabled(cx) {
 1954            key_context.add("jupyter");
 1955        }
 1956
 1957        key_context.set("mode", mode);
 1958        if self.pending_rename.is_some() {
 1959            key_context.add("renaming");
 1960        }
 1961
 1962        match self.context_menu.borrow().as_ref() {
 1963            Some(CodeContextMenu::Completions(_)) => {
 1964                key_context.add("menu");
 1965                key_context.add("showing_completions");
 1966            }
 1967            Some(CodeContextMenu::CodeActions(_)) => {
 1968                key_context.add("menu");
 1969                key_context.add("showing_code_actions")
 1970            }
 1971            None => {}
 1972        }
 1973
 1974        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 1975        if !self.focus_handle(cx).contains_focused(window, cx)
 1976            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 1977        {
 1978            for addon in self.addons.values() {
 1979                addon.extend_key_context(&mut key_context, cx)
 1980            }
 1981        }
 1982
 1983        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 1984            if let Some(extension) = singleton_buffer
 1985                .read(cx)
 1986                .file()
 1987                .and_then(|file| file.path().extension()?.to_str())
 1988            {
 1989                key_context.set("extension", extension.to_string());
 1990            }
 1991        } else {
 1992            key_context.add("multibuffer");
 1993        }
 1994
 1995        if has_active_edit_prediction {
 1996            if self.edit_prediction_in_conflict() {
 1997                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 1998            } else {
 1999                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2000                key_context.add("copilot_suggestion");
 2001            }
 2002        }
 2003
 2004        if self.selection_mark_mode {
 2005            key_context.add("selection_mode");
 2006        }
 2007
 2008        key_context
 2009    }
 2010
 2011    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2012        self.mouse_cursor_hidden = match origin {
 2013            HideMouseCursorOrigin::TypingAction => {
 2014                matches!(
 2015                    self.hide_mouse_mode,
 2016                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2017                )
 2018            }
 2019            HideMouseCursorOrigin::MovementAction => {
 2020                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2021            }
 2022        };
 2023    }
 2024
 2025    pub fn edit_prediction_in_conflict(&self) -> bool {
 2026        if !self.show_edit_predictions_in_menu() {
 2027            return false;
 2028        }
 2029
 2030        let showing_completions = self
 2031            .context_menu
 2032            .borrow()
 2033            .as_ref()
 2034            .map_or(false, |context| {
 2035                matches!(context, CodeContextMenu::Completions(_))
 2036            });
 2037
 2038        showing_completions
 2039            || self.edit_prediction_requires_modifier()
 2040            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2041            // bindings to insert tab characters.
 2042            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2043    }
 2044
 2045    pub fn accept_edit_prediction_keybind(
 2046        &self,
 2047        window: &Window,
 2048        cx: &App,
 2049    ) -> AcceptEditPredictionBinding {
 2050        let key_context = self.key_context_internal(true, window, cx);
 2051        let in_conflict = self.edit_prediction_in_conflict();
 2052
 2053        AcceptEditPredictionBinding(
 2054            window
 2055                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2056                .into_iter()
 2057                .filter(|binding| {
 2058                    !in_conflict
 2059                        || binding
 2060                            .keystrokes()
 2061                            .first()
 2062                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2063                })
 2064                .rev()
 2065                .min_by_key(|binding| {
 2066                    binding
 2067                        .keystrokes()
 2068                        .first()
 2069                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2070                }),
 2071        )
 2072    }
 2073
 2074    pub fn new_file(
 2075        workspace: &mut Workspace,
 2076        _: &workspace::NewFile,
 2077        window: &mut Window,
 2078        cx: &mut Context<Workspace>,
 2079    ) {
 2080        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2081            "Failed to create buffer",
 2082            window,
 2083            cx,
 2084            |e, _, _| match e.error_code() {
 2085                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2086                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2087                e.error_tag("required").unwrap_or("the latest version")
 2088            )),
 2089                _ => None,
 2090            },
 2091        );
 2092    }
 2093
 2094    pub fn new_in_workspace(
 2095        workspace: &mut Workspace,
 2096        window: &mut Window,
 2097        cx: &mut Context<Workspace>,
 2098    ) -> Task<Result<Entity<Editor>>> {
 2099        let project = workspace.project().clone();
 2100        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2101
 2102        cx.spawn_in(window, async move |workspace, cx| {
 2103            let buffer = create.await?;
 2104            workspace.update_in(cx, |workspace, window, cx| {
 2105                let editor =
 2106                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2107                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2108                editor
 2109            })
 2110        })
 2111    }
 2112
 2113    fn new_file_vertical(
 2114        workspace: &mut Workspace,
 2115        _: &workspace::NewFileSplitVertical,
 2116        window: &mut Window,
 2117        cx: &mut Context<Workspace>,
 2118    ) {
 2119        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2120    }
 2121
 2122    fn new_file_horizontal(
 2123        workspace: &mut Workspace,
 2124        _: &workspace::NewFileSplitHorizontal,
 2125        window: &mut Window,
 2126        cx: &mut Context<Workspace>,
 2127    ) {
 2128        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2129    }
 2130
 2131    fn new_file_in_direction(
 2132        workspace: &mut Workspace,
 2133        direction: SplitDirection,
 2134        window: &mut Window,
 2135        cx: &mut Context<Workspace>,
 2136    ) {
 2137        let project = workspace.project().clone();
 2138        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2139
 2140        cx.spawn_in(window, async move |workspace, cx| {
 2141            let buffer = create.await?;
 2142            workspace.update_in(cx, move |workspace, window, cx| {
 2143                workspace.split_item(
 2144                    direction,
 2145                    Box::new(
 2146                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2147                    ),
 2148                    window,
 2149                    cx,
 2150                )
 2151            })?;
 2152            anyhow::Ok(())
 2153        })
 2154        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2155            match e.error_code() {
 2156                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2157                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2158                e.error_tag("required").unwrap_or("the latest version")
 2159            )),
 2160                _ => None,
 2161            }
 2162        });
 2163    }
 2164
 2165    pub fn leader_peer_id(&self) -> Option<PeerId> {
 2166        self.leader_peer_id
 2167    }
 2168
 2169    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2170        &self.buffer
 2171    }
 2172
 2173    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2174        self.workspace.as_ref()?.0.upgrade()
 2175    }
 2176
 2177    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2178        self.buffer().read(cx).title(cx)
 2179    }
 2180
 2181    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2182        let git_blame_gutter_max_author_length = self
 2183            .render_git_blame_gutter(cx)
 2184            .then(|| {
 2185                if let Some(blame) = self.blame.as_ref() {
 2186                    let max_author_length =
 2187                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2188                    Some(max_author_length)
 2189                } else {
 2190                    None
 2191                }
 2192            })
 2193            .flatten();
 2194
 2195        EditorSnapshot {
 2196            mode: self.mode,
 2197            show_gutter: self.show_gutter,
 2198            show_line_numbers: self.show_line_numbers,
 2199            show_git_diff_gutter: self.show_git_diff_gutter,
 2200            show_code_actions: self.show_code_actions,
 2201            show_runnables: self.show_runnables,
 2202            show_breakpoints: self.show_breakpoints,
 2203            git_blame_gutter_max_author_length,
 2204            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2205            scroll_anchor: self.scroll_manager.anchor(),
 2206            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2207            placeholder_text: self.placeholder_text.clone(),
 2208            is_focused: self.focus_handle.is_focused(window),
 2209            current_line_highlight: self
 2210                .current_line_highlight
 2211                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2212            gutter_hovered: self.gutter_hovered,
 2213        }
 2214    }
 2215
 2216    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2217        self.buffer.read(cx).language_at(point, cx)
 2218    }
 2219
 2220    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2221        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2222    }
 2223
 2224    pub fn active_excerpt(
 2225        &self,
 2226        cx: &App,
 2227    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2228        self.buffer
 2229            .read(cx)
 2230            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2231    }
 2232
 2233    pub fn mode(&self) -> EditorMode {
 2234        self.mode
 2235    }
 2236
 2237    pub fn set_mode(&mut self, mode: EditorMode) {
 2238        self.mode = mode;
 2239    }
 2240
 2241    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2242        self.collaboration_hub.as_deref()
 2243    }
 2244
 2245    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2246        self.collaboration_hub = Some(hub);
 2247    }
 2248
 2249    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2250        self.in_project_search = in_project_search;
 2251    }
 2252
 2253    pub fn set_custom_context_menu(
 2254        &mut self,
 2255        f: impl 'static
 2256        + Fn(
 2257            &mut Self,
 2258            DisplayPoint,
 2259            &mut Window,
 2260            &mut Context<Self>,
 2261        ) -> Option<Entity<ui::ContextMenu>>,
 2262    ) {
 2263        self.custom_context_menu = Some(Box::new(f))
 2264    }
 2265
 2266    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2267        self.completion_provider = provider;
 2268    }
 2269
 2270    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2271        self.semantics_provider.clone()
 2272    }
 2273
 2274    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2275        self.semantics_provider = provider;
 2276    }
 2277
 2278    pub fn set_edit_prediction_provider<T>(
 2279        &mut self,
 2280        provider: Option<Entity<T>>,
 2281        window: &mut Window,
 2282        cx: &mut Context<Self>,
 2283    ) where
 2284        T: EditPredictionProvider,
 2285    {
 2286        self.edit_prediction_provider =
 2287            provider.map(|provider| RegisteredInlineCompletionProvider {
 2288                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2289                    if this.focus_handle.is_focused(window) {
 2290                        this.update_visible_inline_completion(window, cx);
 2291                    }
 2292                }),
 2293                provider: Arc::new(provider),
 2294            });
 2295        self.update_edit_prediction_settings(cx);
 2296        self.refresh_inline_completion(false, false, window, cx);
 2297    }
 2298
 2299    pub fn placeholder_text(&self) -> Option<&str> {
 2300        self.placeholder_text.as_deref()
 2301    }
 2302
 2303    pub fn set_placeholder_text(
 2304        &mut self,
 2305        placeholder_text: impl Into<Arc<str>>,
 2306        cx: &mut Context<Self>,
 2307    ) {
 2308        let placeholder_text = Some(placeholder_text.into());
 2309        if self.placeholder_text != placeholder_text {
 2310            self.placeholder_text = placeholder_text;
 2311            cx.notify();
 2312        }
 2313    }
 2314
 2315    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2316        self.cursor_shape = cursor_shape;
 2317
 2318        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2319        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2320
 2321        cx.notify();
 2322    }
 2323
 2324    pub fn set_current_line_highlight(
 2325        &mut self,
 2326        current_line_highlight: Option<CurrentLineHighlight>,
 2327    ) {
 2328        self.current_line_highlight = current_line_highlight;
 2329    }
 2330
 2331    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2332        self.collapse_matches = collapse_matches;
 2333    }
 2334
 2335    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2336        let buffers = self.buffer.read(cx).all_buffers();
 2337        let Some(project) = self.project.as_ref() else {
 2338            return;
 2339        };
 2340        project.update(cx, |project, cx| {
 2341            for buffer in buffers {
 2342                self.registered_buffers
 2343                    .entry(buffer.read(cx).remote_id())
 2344                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2345            }
 2346        })
 2347    }
 2348
 2349    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2350        if self.collapse_matches {
 2351            return range.start..range.start;
 2352        }
 2353        range.clone()
 2354    }
 2355
 2356    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2357        if self.display_map.read(cx).clip_at_line_ends != clip {
 2358            self.display_map
 2359                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2360        }
 2361    }
 2362
 2363    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2364        self.input_enabled = input_enabled;
 2365    }
 2366
 2367    pub fn set_inline_completions_hidden_for_vim_mode(
 2368        &mut self,
 2369        hidden: bool,
 2370        window: &mut Window,
 2371        cx: &mut Context<Self>,
 2372    ) {
 2373        if hidden != self.inline_completions_hidden_for_vim_mode {
 2374            self.inline_completions_hidden_for_vim_mode = hidden;
 2375            if hidden {
 2376                self.update_visible_inline_completion(window, cx);
 2377            } else {
 2378                self.refresh_inline_completion(true, false, window, cx);
 2379            }
 2380        }
 2381    }
 2382
 2383    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2384        self.menu_inline_completions_policy = value;
 2385    }
 2386
 2387    pub fn set_autoindent(&mut self, autoindent: bool) {
 2388        if autoindent {
 2389            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2390        } else {
 2391            self.autoindent_mode = None;
 2392        }
 2393    }
 2394
 2395    pub fn read_only(&self, cx: &App) -> bool {
 2396        self.read_only || self.buffer.read(cx).read_only()
 2397    }
 2398
 2399    pub fn set_read_only(&mut self, read_only: bool) {
 2400        self.read_only = read_only;
 2401    }
 2402
 2403    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2404        self.use_autoclose = autoclose;
 2405    }
 2406
 2407    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2408        self.use_auto_surround = auto_surround;
 2409    }
 2410
 2411    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2412        self.auto_replace_emoji_shortcode = auto_replace;
 2413    }
 2414
 2415    pub fn toggle_edit_predictions(
 2416        &mut self,
 2417        _: &ToggleEditPrediction,
 2418        window: &mut Window,
 2419        cx: &mut Context<Self>,
 2420    ) {
 2421        if self.show_inline_completions_override.is_some() {
 2422            self.set_show_edit_predictions(None, window, cx);
 2423        } else {
 2424            let show_edit_predictions = !self.edit_predictions_enabled();
 2425            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2426        }
 2427    }
 2428
 2429    pub fn set_show_edit_predictions(
 2430        &mut self,
 2431        show_edit_predictions: Option<bool>,
 2432        window: &mut Window,
 2433        cx: &mut Context<Self>,
 2434    ) {
 2435        self.show_inline_completions_override = show_edit_predictions;
 2436        self.update_edit_prediction_settings(cx);
 2437
 2438        if let Some(false) = show_edit_predictions {
 2439            self.discard_inline_completion(false, cx);
 2440        } else {
 2441            self.refresh_inline_completion(false, true, window, cx);
 2442        }
 2443    }
 2444
 2445    fn inline_completions_disabled_in_scope(
 2446        &self,
 2447        buffer: &Entity<Buffer>,
 2448        buffer_position: language::Anchor,
 2449        cx: &App,
 2450    ) -> bool {
 2451        let snapshot = buffer.read(cx).snapshot();
 2452        let settings = snapshot.settings_at(buffer_position, cx);
 2453
 2454        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2455            return false;
 2456        };
 2457
 2458        scope.override_name().map_or(false, |scope_name| {
 2459            settings
 2460                .edit_predictions_disabled_in
 2461                .iter()
 2462                .any(|s| s == scope_name)
 2463        })
 2464    }
 2465
 2466    pub fn set_use_modal_editing(&mut self, to: bool) {
 2467        self.use_modal_editing = to;
 2468    }
 2469
 2470    pub fn use_modal_editing(&self) -> bool {
 2471        self.use_modal_editing
 2472    }
 2473
 2474    fn selections_did_change(
 2475        &mut self,
 2476        local: bool,
 2477        old_cursor_position: &Anchor,
 2478        show_completions: bool,
 2479        window: &mut Window,
 2480        cx: &mut Context<Self>,
 2481    ) {
 2482        window.invalidate_character_coordinates();
 2483
 2484        // Copy selections to primary selection buffer
 2485        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2486        if local {
 2487            let selections = self.selections.all::<usize>(cx);
 2488            let buffer_handle = self.buffer.read(cx).read(cx);
 2489
 2490            let mut text = String::new();
 2491            for (index, selection) in selections.iter().enumerate() {
 2492                let text_for_selection = buffer_handle
 2493                    .text_for_range(selection.start..selection.end)
 2494                    .collect::<String>();
 2495
 2496                text.push_str(&text_for_selection);
 2497                if index != selections.len() - 1 {
 2498                    text.push('\n');
 2499                }
 2500            }
 2501
 2502            if !text.is_empty() {
 2503                cx.write_to_primary(ClipboardItem::new_string(text));
 2504            }
 2505        }
 2506
 2507        if self.focus_handle.is_focused(window) && self.leader_peer_id.is_none() {
 2508            self.buffer.update(cx, |buffer, cx| {
 2509                buffer.set_active_selections(
 2510                    &self.selections.disjoint_anchors(),
 2511                    self.selections.line_mode,
 2512                    self.cursor_shape,
 2513                    cx,
 2514                )
 2515            });
 2516        }
 2517        let display_map = self
 2518            .display_map
 2519            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2520        let buffer = &display_map.buffer_snapshot;
 2521        self.add_selections_state = None;
 2522        self.select_next_state = None;
 2523        self.select_prev_state = None;
 2524        self.select_syntax_node_history.try_clear();
 2525        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2526        self.snippet_stack
 2527            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2528        self.take_rename(false, window, cx);
 2529
 2530        let new_cursor_position = self.selections.newest_anchor().head();
 2531
 2532        self.push_to_nav_history(
 2533            *old_cursor_position,
 2534            Some(new_cursor_position.to_point(buffer)),
 2535            false,
 2536            cx,
 2537        );
 2538
 2539        if local {
 2540            let new_cursor_position = self.selections.newest_anchor().head();
 2541            let mut context_menu = self.context_menu.borrow_mut();
 2542            let completion_menu = match context_menu.as_ref() {
 2543                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2544                _ => {
 2545                    *context_menu = None;
 2546                    None
 2547                }
 2548            };
 2549            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2550                if !self.registered_buffers.contains_key(&buffer_id) {
 2551                    if let Some(project) = self.project.as_ref() {
 2552                        project.update(cx, |project, cx| {
 2553                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2554                                return;
 2555                            };
 2556                            self.registered_buffers.insert(
 2557                                buffer_id,
 2558                                project.register_buffer_with_language_servers(&buffer, cx),
 2559                            );
 2560                        })
 2561                    }
 2562                }
 2563            }
 2564
 2565            if let Some(completion_menu) = completion_menu {
 2566                let cursor_position = new_cursor_position.to_offset(buffer);
 2567                let (word_range, kind) =
 2568                    buffer.surrounding_word(completion_menu.initial_position, true);
 2569                if kind == Some(CharKind::Word)
 2570                    && word_range.to_inclusive().contains(&cursor_position)
 2571                {
 2572                    let mut completion_menu = completion_menu.clone();
 2573                    drop(context_menu);
 2574
 2575                    let query = Self::completion_query(buffer, cursor_position);
 2576                    cx.spawn(async move |this, cx| {
 2577                        completion_menu
 2578                            .filter(query.as_deref(), cx.background_executor().clone())
 2579                            .await;
 2580
 2581                        this.update(cx, |this, cx| {
 2582                            let mut context_menu = this.context_menu.borrow_mut();
 2583                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2584                            else {
 2585                                return;
 2586                            };
 2587
 2588                            if menu.id > completion_menu.id {
 2589                                return;
 2590                            }
 2591
 2592                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2593                            drop(context_menu);
 2594                            cx.notify();
 2595                        })
 2596                    })
 2597                    .detach();
 2598
 2599                    if show_completions {
 2600                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2601                    }
 2602                } else {
 2603                    drop(context_menu);
 2604                    self.hide_context_menu(window, cx);
 2605                }
 2606            } else {
 2607                drop(context_menu);
 2608            }
 2609
 2610            hide_hover(self, cx);
 2611
 2612            if old_cursor_position.to_display_point(&display_map).row()
 2613                != new_cursor_position.to_display_point(&display_map).row()
 2614            {
 2615                self.available_code_actions.take();
 2616            }
 2617            self.refresh_code_actions(window, cx);
 2618            self.refresh_document_highlights(cx);
 2619            self.refresh_selected_text_highlights(window, cx);
 2620            refresh_matching_bracket_highlights(self, window, cx);
 2621            self.update_visible_inline_completion(window, cx);
 2622            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2623            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2624            self.inline_blame_popover.take();
 2625            if self.git_blame_inline_enabled {
 2626                self.start_inline_blame_timer(window, cx);
 2627            }
 2628        }
 2629
 2630        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2631        cx.emit(EditorEvent::SelectionsChanged { local });
 2632
 2633        let selections = &self.selections.disjoint;
 2634        if selections.len() == 1 {
 2635            cx.emit(SearchEvent::ActiveMatchChanged)
 2636        }
 2637        if local {
 2638            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2639                let inmemory_selections = selections
 2640                    .iter()
 2641                    .map(|s| {
 2642                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2643                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2644                    })
 2645                    .collect();
 2646                self.update_restoration_data(cx, |data| {
 2647                    data.selections = inmemory_selections;
 2648                });
 2649
 2650                if WorkspaceSettings::get(None, cx).restore_on_startup
 2651                    != RestoreOnStartupBehavior::None
 2652                {
 2653                    if let Some(workspace_id) =
 2654                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2655                    {
 2656                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2657                        let selections = selections.clone();
 2658                        let background_executor = cx.background_executor().clone();
 2659                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2660                        self.serialize_selections = cx.background_spawn(async move {
 2661                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2662                    let db_selections = selections
 2663                        .iter()
 2664                        .map(|selection| {
 2665                            (
 2666                                selection.start.to_offset(&snapshot),
 2667                                selection.end.to_offset(&snapshot),
 2668                            )
 2669                        })
 2670                        .collect();
 2671
 2672                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2673                        .await
 2674                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2675                        .log_err();
 2676                });
 2677                    }
 2678                }
 2679            }
 2680        }
 2681
 2682        cx.notify();
 2683    }
 2684
 2685    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2686        use text::ToOffset as _;
 2687        use text::ToPoint as _;
 2688
 2689        if WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None {
 2690            return;
 2691        }
 2692
 2693        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2694            return;
 2695        };
 2696
 2697        let snapshot = singleton.read(cx).snapshot();
 2698        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2699            let display_snapshot = display_map.snapshot(cx);
 2700
 2701            display_snapshot
 2702                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2703                .map(|fold| {
 2704                    fold.range.start.text_anchor.to_point(&snapshot)
 2705                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2706                })
 2707                .collect()
 2708        });
 2709        self.update_restoration_data(cx, |data| {
 2710            data.folds = inmemory_folds;
 2711        });
 2712
 2713        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2714            return;
 2715        };
 2716        let background_executor = cx.background_executor().clone();
 2717        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2718        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2719            display_map
 2720                .snapshot(cx)
 2721                .folds_in_range(0..snapshot.len())
 2722                .map(|fold| {
 2723                    (
 2724                        fold.range.start.text_anchor.to_offset(&snapshot),
 2725                        fold.range.end.text_anchor.to_offset(&snapshot),
 2726                    )
 2727                })
 2728                .collect()
 2729        });
 2730        self.serialize_folds = cx.background_spawn(async move {
 2731            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2732            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2733                .await
 2734                .with_context(|| {
 2735                    format!(
 2736                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2737                    )
 2738                })
 2739                .log_err();
 2740        });
 2741    }
 2742
 2743    pub fn sync_selections(
 2744        &mut self,
 2745        other: Entity<Editor>,
 2746        cx: &mut Context<Self>,
 2747    ) -> gpui::Subscription {
 2748        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2749        self.selections.change_with(cx, |selections| {
 2750            selections.select_anchors(other_selections);
 2751        });
 2752
 2753        let other_subscription =
 2754            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2755                EditorEvent::SelectionsChanged { local: true } => {
 2756                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2757                    if other_selections.is_empty() {
 2758                        return;
 2759                    }
 2760                    this.selections.change_with(cx, |selections| {
 2761                        selections.select_anchors(other_selections);
 2762                    });
 2763                }
 2764                _ => {}
 2765            });
 2766
 2767        let this_subscription =
 2768            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2769                EditorEvent::SelectionsChanged { local: true } => {
 2770                    let these_selections = this.selections.disjoint.to_vec();
 2771                    if these_selections.is_empty() {
 2772                        return;
 2773                    }
 2774                    other.update(cx, |other_editor, cx| {
 2775                        other_editor.selections.change_with(cx, |selections| {
 2776                            selections.select_anchors(these_selections);
 2777                        })
 2778                    });
 2779                }
 2780                _ => {}
 2781            });
 2782
 2783        Subscription::join(other_subscription, this_subscription)
 2784    }
 2785
 2786    pub fn change_selections<R>(
 2787        &mut self,
 2788        autoscroll: Option<Autoscroll>,
 2789        window: &mut Window,
 2790        cx: &mut Context<Self>,
 2791        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2792    ) -> R {
 2793        self.change_selections_inner(autoscroll, true, window, cx, change)
 2794    }
 2795
 2796    fn change_selections_inner<R>(
 2797        &mut self,
 2798        autoscroll: Option<Autoscroll>,
 2799        request_completions: bool,
 2800        window: &mut Window,
 2801        cx: &mut Context<Self>,
 2802        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2803    ) -> R {
 2804        let old_cursor_position = self.selections.newest_anchor().head();
 2805        self.push_to_selection_history();
 2806
 2807        let (changed, result) = self.selections.change_with(cx, change);
 2808
 2809        if changed {
 2810            if let Some(autoscroll) = autoscroll {
 2811                self.request_autoscroll(autoscroll, cx);
 2812            }
 2813            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2814
 2815            if self.should_open_signature_help_automatically(
 2816                &old_cursor_position,
 2817                self.signature_help_state.backspace_pressed(),
 2818                cx,
 2819            ) {
 2820                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2821            }
 2822            self.signature_help_state.set_backspace_pressed(false);
 2823        }
 2824
 2825        result
 2826    }
 2827
 2828    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2829    where
 2830        I: IntoIterator<Item = (Range<S>, T)>,
 2831        S: ToOffset,
 2832        T: Into<Arc<str>>,
 2833    {
 2834        if self.read_only(cx) {
 2835            return;
 2836        }
 2837
 2838        self.buffer
 2839            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2840    }
 2841
 2842    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2843    where
 2844        I: IntoIterator<Item = (Range<S>, T)>,
 2845        S: ToOffset,
 2846        T: Into<Arc<str>>,
 2847    {
 2848        if self.read_only(cx) {
 2849            return;
 2850        }
 2851
 2852        self.buffer.update(cx, |buffer, cx| {
 2853            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2854        });
 2855    }
 2856
 2857    pub fn edit_with_block_indent<I, S, T>(
 2858        &mut self,
 2859        edits: I,
 2860        original_indent_columns: Vec<Option<u32>>,
 2861        cx: &mut Context<Self>,
 2862    ) where
 2863        I: IntoIterator<Item = (Range<S>, T)>,
 2864        S: ToOffset,
 2865        T: Into<Arc<str>>,
 2866    {
 2867        if self.read_only(cx) {
 2868            return;
 2869        }
 2870
 2871        self.buffer.update(cx, |buffer, cx| {
 2872            buffer.edit(
 2873                edits,
 2874                Some(AutoindentMode::Block {
 2875                    original_indent_columns,
 2876                }),
 2877                cx,
 2878            )
 2879        });
 2880    }
 2881
 2882    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2883        self.hide_context_menu(window, cx);
 2884
 2885        match phase {
 2886            SelectPhase::Begin {
 2887                position,
 2888                add,
 2889                click_count,
 2890            } => self.begin_selection(position, add, click_count, window, cx),
 2891            SelectPhase::BeginColumnar {
 2892                position,
 2893                goal_column,
 2894                reset,
 2895            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 2896            SelectPhase::Extend {
 2897                position,
 2898                click_count,
 2899            } => self.extend_selection(position, click_count, window, cx),
 2900            SelectPhase::Update {
 2901                position,
 2902                goal_column,
 2903                scroll_delta,
 2904            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 2905            SelectPhase::End => self.end_selection(window, cx),
 2906        }
 2907    }
 2908
 2909    fn extend_selection(
 2910        &mut self,
 2911        position: DisplayPoint,
 2912        click_count: usize,
 2913        window: &mut Window,
 2914        cx: &mut Context<Self>,
 2915    ) {
 2916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2917        let tail = self.selections.newest::<usize>(cx).tail();
 2918        self.begin_selection(position, false, click_count, window, cx);
 2919
 2920        let position = position.to_offset(&display_map, Bias::Left);
 2921        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2922
 2923        let mut pending_selection = self
 2924            .selections
 2925            .pending_anchor()
 2926            .expect("extend_selection not called with pending selection");
 2927        if position >= tail {
 2928            pending_selection.start = tail_anchor;
 2929        } else {
 2930            pending_selection.end = tail_anchor;
 2931            pending_selection.reversed = true;
 2932        }
 2933
 2934        let mut pending_mode = self.selections.pending_mode().unwrap();
 2935        match &mut pending_mode {
 2936            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2937            _ => {}
 2938        }
 2939
 2940        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 2941            s.set_pending(pending_selection, pending_mode)
 2942        });
 2943    }
 2944
 2945    fn begin_selection(
 2946        &mut self,
 2947        position: DisplayPoint,
 2948        add: bool,
 2949        click_count: usize,
 2950        window: &mut Window,
 2951        cx: &mut Context<Self>,
 2952    ) {
 2953        if !self.focus_handle.is_focused(window) {
 2954            self.last_focused_descendant = None;
 2955            window.focus(&self.focus_handle);
 2956        }
 2957
 2958        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2959        let buffer = &display_map.buffer_snapshot;
 2960        let newest_selection = self.selections.newest_anchor().clone();
 2961        let position = display_map.clip_point(position, Bias::Left);
 2962
 2963        let start;
 2964        let end;
 2965        let mode;
 2966        let mut auto_scroll;
 2967        match click_count {
 2968            1 => {
 2969                start = buffer.anchor_before(position.to_point(&display_map));
 2970                end = start;
 2971                mode = SelectMode::Character;
 2972                auto_scroll = true;
 2973            }
 2974            2 => {
 2975                let range = movement::surrounding_word(&display_map, position);
 2976                start = buffer.anchor_before(range.start.to_point(&display_map));
 2977                end = buffer.anchor_before(range.end.to_point(&display_map));
 2978                mode = SelectMode::Word(start..end);
 2979                auto_scroll = true;
 2980            }
 2981            3 => {
 2982                let position = display_map
 2983                    .clip_point(position, Bias::Left)
 2984                    .to_point(&display_map);
 2985                let line_start = display_map.prev_line_boundary(position).0;
 2986                let next_line_start = buffer.clip_point(
 2987                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2988                    Bias::Left,
 2989                );
 2990                start = buffer.anchor_before(line_start);
 2991                end = buffer.anchor_before(next_line_start);
 2992                mode = SelectMode::Line(start..end);
 2993                auto_scroll = true;
 2994            }
 2995            _ => {
 2996                start = buffer.anchor_before(0);
 2997                end = buffer.anchor_before(buffer.len());
 2998                mode = SelectMode::All;
 2999                auto_scroll = false;
 3000            }
 3001        }
 3002        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3003
 3004        let point_to_delete: Option<usize> = {
 3005            let selected_points: Vec<Selection<Point>> =
 3006                self.selections.disjoint_in_range(start..end, cx);
 3007
 3008            if !add || click_count > 1 {
 3009                None
 3010            } else if !selected_points.is_empty() {
 3011                Some(selected_points[0].id)
 3012            } else {
 3013                let clicked_point_already_selected =
 3014                    self.selections.disjoint.iter().find(|selection| {
 3015                        selection.start.to_point(buffer) == start.to_point(buffer)
 3016                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3017                    });
 3018
 3019                clicked_point_already_selected.map(|selection| selection.id)
 3020            }
 3021        };
 3022
 3023        let selections_count = self.selections.count();
 3024
 3025        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3026            if let Some(point_to_delete) = point_to_delete {
 3027                s.delete(point_to_delete);
 3028
 3029                if selections_count == 1 {
 3030                    s.set_pending_anchor_range(start..end, mode);
 3031                }
 3032            } else {
 3033                if !add {
 3034                    s.clear_disjoint();
 3035                } else if click_count > 1 {
 3036                    s.delete(newest_selection.id)
 3037                }
 3038
 3039                s.set_pending_anchor_range(start..end, mode);
 3040            }
 3041        });
 3042    }
 3043
 3044    fn begin_columnar_selection(
 3045        &mut self,
 3046        position: DisplayPoint,
 3047        goal_column: u32,
 3048        reset: bool,
 3049        window: &mut Window,
 3050        cx: &mut Context<Self>,
 3051    ) {
 3052        if !self.focus_handle.is_focused(window) {
 3053            self.last_focused_descendant = None;
 3054            window.focus(&self.focus_handle);
 3055        }
 3056
 3057        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3058
 3059        if reset {
 3060            let pointer_position = display_map
 3061                .buffer_snapshot
 3062                .anchor_before(position.to_point(&display_map));
 3063
 3064            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3065                s.clear_disjoint();
 3066                s.set_pending_anchor_range(
 3067                    pointer_position..pointer_position,
 3068                    SelectMode::Character,
 3069                );
 3070            });
 3071        }
 3072
 3073        let tail = self.selections.newest::<Point>(cx).tail();
 3074        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3075
 3076        if !reset {
 3077            self.select_columns(
 3078                tail.to_display_point(&display_map),
 3079                position,
 3080                goal_column,
 3081                &display_map,
 3082                window,
 3083                cx,
 3084            );
 3085        }
 3086    }
 3087
 3088    fn update_selection(
 3089        &mut self,
 3090        position: DisplayPoint,
 3091        goal_column: u32,
 3092        scroll_delta: gpui::Point<f32>,
 3093        window: &mut Window,
 3094        cx: &mut Context<Self>,
 3095    ) {
 3096        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3097
 3098        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3099            let tail = tail.to_display_point(&display_map);
 3100            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3101        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3102            let buffer = self.buffer.read(cx).snapshot(cx);
 3103            let head;
 3104            let tail;
 3105            let mode = self.selections.pending_mode().unwrap();
 3106            match &mode {
 3107                SelectMode::Character => {
 3108                    head = position.to_point(&display_map);
 3109                    tail = pending.tail().to_point(&buffer);
 3110                }
 3111                SelectMode::Word(original_range) => {
 3112                    let original_display_range = original_range.start.to_display_point(&display_map)
 3113                        ..original_range.end.to_display_point(&display_map);
 3114                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3115                        ..original_display_range.end.to_point(&display_map);
 3116                    if movement::is_inside_word(&display_map, position)
 3117                        || original_display_range.contains(&position)
 3118                    {
 3119                        let word_range = movement::surrounding_word(&display_map, position);
 3120                        if word_range.start < original_display_range.start {
 3121                            head = word_range.start.to_point(&display_map);
 3122                        } else {
 3123                            head = word_range.end.to_point(&display_map);
 3124                        }
 3125                    } else {
 3126                        head = position.to_point(&display_map);
 3127                    }
 3128
 3129                    if head <= original_buffer_range.start {
 3130                        tail = original_buffer_range.end;
 3131                    } else {
 3132                        tail = original_buffer_range.start;
 3133                    }
 3134                }
 3135                SelectMode::Line(original_range) => {
 3136                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3137
 3138                    let position = display_map
 3139                        .clip_point(position, Bias::Left)
 3140                        .to_point(&display_map);
 3141                    let line_start = display_map.prev_line_boundary(position).0;
 3142                    let next_line_start = buffer.clip_point(
 3143                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3144                        Bias::Left,
 3145                    );
 3146
 3147                    if line_start < original_range.start {
 3148                        head = line_start
 3149                    } else {
 3150                        head = next_line_start
 3151                    }
 3152
 3153                    if head <= original_range.start {
 3154                        tail = original_range.end;
 3155                    } else {
 3156                        tail = original_range.start;
 3157                    }
 3158                }
 3159                SelectMode::All => {
 3160                    return;
 3161                }
 3162            };
 3163
 3164            if head < tail {
 3165                pending.start = buffer.anchor_before(head);
 3166                pending.end = buffer.anchor_before(tail);
 3167                pending.reversed = true;
 3168            } else {
 3169                pending.start = buffer.anchor_before(tail);
 3170                pending.end = buffer.anchor_before(head);
 3171                pending.reversed = false;
 3172            }
 3173
 3174            self.change_selections(None, window, cx, |s| {
 3175                s.set_pending(pending, mode);
 3176            });
 3177        } else {
 3178            log::error!("update_selection dispatched with no pending selection");
 3179            return;
 3180        }
 3181
 3182        self.apply_scroll_delta(scroll_delta, window, cx);
 3183        cx.notify();
 3184    }
 3185
 3186    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3187        self.columnar_selection_tail.take();
 3188        if self.selections.pending_anchor().is_some() {
 3189            let selections = self.selections.all::<usize>(cx);
 3190            self.change_selections(None, window, cx, |s| {
 3191                s.select(selections);
 3192                s.clear_pending();
 3193            });
 3194        }
 3195    }
 3196
 3197    fn select_columns(
 3198        &mut self,
 3199        tail: DisplayPoint,
 3200        head: DisplayPoint,
 3201        goal_column: u32,
 3202        display_map: &DisplaySnapshot,
 3203        window: &mut Window,
 3204        cx: &mut Context<Self>,
 3205    ) {
 3206        let start_row = cmp::min(tail.row(), head.row());
 3207        let end_row = cmp::max(tail.row(), head.row());
 3208        let start_column = cmp::min(tail.column(), goal_column);
 3209        let end_column = cmp::max(tail.column(), goal_column);
 3210        let reversed = start_column < tail.column();
 3211
 3212        let selection_ranges = (start_row.0..=end_row.0)
 3213            .map(DisplayRow)
 3214            .filter_map(|row| {
 3215                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3216                    let start = display_map
 3217                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3218                        .to_point(display_map);
 3219                    let end = display_map
 3220                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3221                        .to_point(display_map);
 3222                    if reversed {
 3223                        Some(end..start)
 3224                    } else {
 3225                        Some(start..end)
 3226                    }
 3227                } else {
 3228                    None
 3229                }
 3230            })
 3231            .collect::<Vec<_>>();
 3232
 3233        self.change_selections(None, window, cx, |s| {
 3234            s.select_ranges(selection_ranges);
 3235        });
 3236        cx.notify();
 3237    }
 3238
 3239    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3240        self.selections
 3241            .all_adjusted(cx)
 3242            .iter()
 3243            .any(|selection| !selection.is_empty())
 3244    }
 3245
 3246    pub fn has_pending_nonempty_selection(&self) -> bool {
 3247        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3248            Some(Selection { start, end, .. }) => start != end,
 3249            None => false,
 3250        };
 3251
 3252        pending_nonempty_selection
 3253            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3254    }
 3255
 3256    pub fn has_pending_selection(&self) -> bool {
 3257        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3258    }
 3259
 3260    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3261        self.selection_mark_mode = false;
 3262
 3263        if self.clear_expanded_diff_hunks(cx) {
 3264            cx.notify();
 3265            return;
 3266        }
 3267        if self.dismiss_menus_and_popups(true, window, cx) {
 3268            return;
 3269        }
 3270
 3271        if self.mode.is_full()
 3272            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3273        {
 3274            return;
 3275        }
 3276
 3277        cx.propagate();
 3278    }
 3279
 3280    pub fn dismiss_menus_and_popups(
 3281        &mut self,
 3282        is_user_requested: bool,
 3283        window: &mut Window,
 3284        cx: &mut Context<Self>,
 3285    ) -> bool {
 3286        if self.take_rename(false, window, cx).is_some() {
 3287            return true;
 3288        }
 3289
 3290        if hide_hover(self, cx) {
 3291            return true;
 3292        }
 3293
 3294        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3295            return true;
 3296        }
 3297
 3298        if self.hide_context_menu(window, cx).is_some() {
 3299            return true;
 3300        }
 3301
 3302        if self.mouse_context_menu.take().is_some() {
 3303            return true;
 3304        }
 3305
 3306        if is_user_requested && self.discard_inline_completion(true, cx) {
 3307            return true;
 3308        }
 3309
 3310        if self.snippet_stack.pop().is_some() {
 3311            return true;
 3312        }
 3313
 3314        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3315            self.dismiss_diagnostics(cx);
 3316            return true;
 3317        }
 3318
 3319        false
 3320    }
 3321
 3322    fn linked_editing_ranges_for(
 3323        &self,
 3324        selection: Range<text::Anchor>,
 3325        cx: &App,
 3326    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3327        if self.linked_edit_ranges.is_empty() {
 3328            return None;
 3329        }
 3330        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3331            selection.end.buffer_id.and_then(|end_buffer_id| {
 3332                if selection.start.buffer_id != Some(end_buffer_id) {
 3333                    return None;
 3334                }
 3335                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3336                let snapshot = buffer.read(cx).snapshot();
 3337                self.linked_edit_ranges
 3338                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3339                    .map(|ranges| (ranges, snapshot, buffer))
 3340            })?;
 3341        use text::ToOffset as TO;
 3342        // find offset from the start of current range to current cursor position
 3343        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3344
 3345        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3346        let start_difference = start_offset - start_byte_offset;
 3347        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3348        let end_difference = end_offset - start_byte_offset;
 3349        // Current range has associated linked ranges.
 3350        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3351        for range in linked_ranges.iter() {
 3352            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3353            let end_offset = start_offset + end_difference;
 3354            let start_offset = start_offset + start_difference;
 3355            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3356                continue;
 3357            }
 3358            if self.selections.disjoint_anchor_ranges().any(|s| {
 3359                if s.start.buffer_id != selection.start.buffer_id
 3360                    || s.end.buffer_id != selection.end.buffer_id
 3361                {
 3362                    return false;
 3363                }
 3364                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3365                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3366            }) {
 3367                continue;
 3368            }
 3369            let start = buffer_snapshot.anchor_after(start_offset);
 3370            let end = buffer_snapshot.anchor_after(end_offset);
 3371            linked_edits
 3372                .entry(buffer.clone())
 3373                .or_default()
 3374                .push(start..end);
 3375        }
 3376        Some(linked_edits)
 3377    }
 3378
 3379    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3380        let text: Arc<str> = text.into();
 3381
 3382        if self.read_only(cx) {
 3383            return;
 3384        }
 3385
 3386        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3387
 3388        let selections = self.selections.all_adjusted(cx);
 3389        let mut bracket_inserted = false;
 3390        let mut edits = Vec::new();
 3391        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3392        let mut new_selections = Vec::with_capacity(selections.len());
 3393        let mut new_autoclose_regions = Vec::new();
 3394        let snapshot = self.buffer.read(cx).read(cx);
 3395        let mut clear_linked_edit_ranges = false;
 3396
 3397        for (selection, autoclose_region) in
 3398            self.selections_with_autoclose_regions(selections, &snapshot)
 3399        {
 3400            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3401                // Determine if the inserted text matches the opening or closing
 3402                // bracket of any of this language's bracket pairs.
 3403                let mut bracket_pair = None;
 3404                let mut is_bracket_pair_start = false;
 3405                let mut is_bracket_pair_end = false;
 3406                if !text.is_empty() {
 3407                    let mut bracket_pair_matching_end = None;
 3408                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3409                    //  and they are removing the character that triggered IME popup.
 3410                    for (pair, enabled) in scope.brackets() {
 3411                        if !pair.close && !pair.surround {
 3412                            continue;
 3413                        }
 3414
 3415                        if enabled && pair.start.ends_with(text.as_ref()) {
 3416                            let prefix_len = pair.start.len() - text.len();
 3417                            let preceding_text_matches_prefix = prefix_len == 0
 3418                                || (selection.start.column >= (prefix_len as u32)
 3419                                    && snapshot.contains_str_at(
 3420                                        Point::new(
 3421                                            selection.start.row,
 3422                                            selection.start.column - (prefix_len as u32),
 3423                                        ),
 3424                                        &pair.start[..prefix_len],
 3425                                    ));
 3426                            if preceding_text_matches_prefix {
 3427                                bracket_pair = Some(pair.clone());
 3428                                is_bracket_pair_start = true;
 3429                                break;
 3430                            }
 3431                        }
 3432                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3433                        {
 3434                            // take first bracket pair matching end, but don't break in case a later bracket
 3435                            // pair matches start
 3436                            bracket_pair_matching_end = Some(pair.clone());
 3437                        }
 3438                    }
 3439                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3440                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3441                        is_bracket_pair_end = true;
 3442                    }
 3443                }
 3444
 3445                if let Some(bracket_pair) = bracket_pair {
 3446                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3447                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3448                    let auto_surround =
 3449                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3450                    if selection.is_empty() {
 3451                        if is_bracket_pair_start {
 3452                            // If the inserted text is a suffix of an opening bracket and the
 3453                            // selection is preceded by the rest of the opening bracket, then
 3454                            // insert the closing bracket.
 3455                            let following_text_allows_autoclose = snapshot
 3456                                .chars_at(selection.start)
 3457                                .next()
 3458                                .map_or(true, |c| scope.should_autoclose_before(c));
 3459
 3460                            let preceding_text_allows_autoclose = selection.start.column == 0
 3461                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3462                                    true,
 3463                                    |c| {
 3464                                        bracket_pair.start != bracket_pair.end
 3465                                            || !snapshot
 3466                                                .char_classifier_at(selection.start)
 3467                                                .is_word(c)
 3468                                    },
 3469                                );
 3470
 3471                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3472                                && bracket_pair.start.len() == 1
 3473                            {
 3474                                let target = bracket_pair.start.chars().next().unwrap();
 3475                                let current_line_count = snapshot
 3476                                    .reversed_chars_at(selection.start)
 3477                                    .take_while(|&c| c != '\n')
 3478                                    .filter(|&c| c == target)
 3479                                    .count();
 3480                                current_line_count % 2 == 1
 3481                            } else {
 3482                                false
 3483                            };
 3484
 3485                            if autoclose
 3486                                && bracket_pair.close
 3487                                && following_text_allows_autoclose
 3488                                && preceding_text_allows_autoclose
 3489                                && !is_closing_quote
 3490                            {
 3491                                let anchor = snapshot.anchor_before(selection.end);
 3492                                new_selections.push((selection.map(|_| anchor), text.len()));
 3493                                new_autoclose_regions.push((
 3494                                    anchor,
 3495                                    text.len(),
 3496                                    selection.id,
 3497                                    bracket_pair.clone(),
 3498                                ));
 3499                                edits.push((
 3500                                    selection.range(),
 3501                                    format!("{}{}", text, bracket_pair.end).into(),
 3502                                ));
 3503                                bracket_inserted = true;
 3504                                continue;
 3505                            }
 3506                        }
 3507
 3508                        if let Some(region) = autoclose_region {
 3509                            // If the selection is followed by an auto-inserted closing bracket,
 3510                            // then don't insert that closing bracket again; just move the selection
 3511                            // past the closing bracket.
 3512                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3513                                && text.as_ref() == region.pair.end.as_str();
 3514                            if should_skip {
 3515                                let anchor = snapshot.anchor_after(selection.end);
 3516                                new_selections
 3517                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3518                                continue;
 3519                            }
 3520                        }
 3521
 3522                        let always_treat_brackets_as_autoclosed = snapshot
 3523                            .language_settings_at(selection.start, cx)
 3524                            .always_treat_brackets_as_autoclosed;
 3525                        if always_treat_brackets_as_autoclosed
 3526                            && is_bracket_pair_end
 3527                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3528                        {
 3529                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3530                            // and the inserted text is a closing bracket and the selection is followed
 3531                            // by the closing bracket then move the selection past the closing bracket.
 3532                            let anchor = snapshot.anchor_after(selection.end);
 3533                            new_selections.push((selection.map(|_| anchor), text.len()));
 3534                            continue;
 3535                        }
 3536                    }
 3537                    // If an opening bracket is 1 character long and is typed while
 3538                    // text is selected, then surround that text with the bracket pair.
 3539                    else if auto_surround
 3540                        && bracket_pair.surround
 3541                        && is_bracket_pair_start
 3542                        && bracket_pair.start.chars().count() == 1
 3543                    {
 3544                        edits.push((selection.start..selection.start, text.clone()));
 3545                        edits.push((
 3546                            selection.end..selection.end,
 3547                            bracket_pair.end.as_str().into(),
 3548                        ));
 3549                        bracket_inserted = true;
 3550                        new_selections.push((
 3551                            Selection {
 3552                                id: selection.id,
 3553                                start: snapshot.anchor_after(selection.start),
 3554                                end: snapshot.anchor_before(selection.end),
 3555                                reversed: selection.reversed,
 3556                                goal: selection.goal,
 3557                            },
 3558                            0,
 3559                        ));
 3560                        continue;
 3561                    }
 3562                }
 3563            }
 3564
 3565            if self.auto_replace_emoji_shortcode
 3566                && selection.is_empty()
 3567                && text.as_ref().ends_with(':')
 3568            {
 3569                if let Some(possible_emoji_short_code) =
 3570                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3571                {
 3572                    if !possible_emoji_short_code.is_empty() {
 3573                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3574                            let emoji_shortcode_start = Point::new(
 3575                                selection.start.row,
 3576                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3577                            );
 3578
 3579                            // Remove shortcode from buffer
 3580                            edits.push((
 3581                                emoji_shortcode_start..selection.start,
 3582                                "".to_string().into(),
 3583                            ));
 3584                            new_selections.push((
 3585                                Selection {
 3586                                    id: selection.id,
 3587                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3588                                    end: snapshot.anchor_before(selection.start),
 3589                                    reversed: selection.reversed,
 3590                                    goal: selection.goal,
 3591                                },
 3592                                0,
 3593                            ));
 3594
 3595                            // Insert emoji
 3596                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3597                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3598                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3599
 3600                            continue;
 3601                        }
 3602                    }
 3603                }
 3604            }
 3605
 3606            // If not handling any auto-close operation, then just replace the selected
 3607            // text with the given input and move the selection to the end of the
 3608            // newly inserted text.
 3609            let anchor = snapshot.anchor_after(selection.end);
 3610            if !self.linked_edit_ranges.is_empty() {
 3611                let start_anchor = snapshot.anchor_before(selection.start);
 3612
 3613                let is_word_char = text.chars().next().map_or(true, |char| {
 3614                    let classifier = snapshot.char_classifier_at(start_anchor.to_offset(&snapshot));
 3615                    classifier.is_word(char)
 3616                });
 3617
 3618                if is_word_char {
 3619                    if let Some(ranges) = self
 3620                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3621                    {
 3622                        for (buffer, edits) in ranges {
 3623                            linked_edits
 3624                                .entry(buffer.clone())
 3625                                .or_default()
 3626                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3627                        }
 3628                    }
 3629                } else {
 3630                    clear_linked_edit_ranges = true;
 3631                }
 3632            }
 3633
 3634            new_selections.push((selection.map(|_| anchor), 0));
 3635            edits.push((selection.start..selection.end, text.clone()));
 3636        }
 3637
 3638        drop(snapshot);
 3639
 3640        self.transact(window, cx, |this, window, cx| {
 3641            if clear_linked_edit_ranges {
 3642                this.linked_edit_ranges.clear();
 3643            }
 3644            let initial_buffer_versions =
 3645                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3646
 3647            this.buffer.update(cx, |buffer, cx| {
 3648                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3649            });
 3650            for (buffer, edits) in linked_edits {
 3651                buffer.update(cx, |buffer, cx| {
 3652                    let snapshot = buffer.snapshot();
 3653                    let edits = edits
 3654                        .into_iter()
 3655                        .map(|(range, text)| {
 3656                            use text::ToPoint as TP;
 3657                            let end_point = TP::to_point(&range.end, &snapshot);
 3658                            let start_point = TP::to_point(&range.start, &snapshot);
 3659                            (start_point..end_point, text)
 3660                        })
 3661                        .sorted_by_key(|(range, _)| range.start);
 3662                    buffer.edit(edits, None, cx);
 3663                })
 3664            }
 3665            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3666            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3667            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3668            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3669                .zip(new_selection_deltas)
 3670                .map(|(selection, delta)| Selection {
 3671                    id: selection.id,
 3672                    start: selection.start + delta,
 3673                    end: selection.end + delta,
 3674                    reversed: selection.reversed,
 3675                    goal: SelectionGoal::None,
 3676                })
 3677                .collect::<Vec<_>>();
 3678
 3679            let mut i = 0;
 3680            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3681                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3682                let start = map.buffer_snapshot.anchor_before(position);
 3683                let end = map.buffer_snapshot.anchor_after(position);
 3684                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3685                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3686                        Ordering::Less => i += 1,
 3687                        Ordering::Greater => break,
 3688                        Ordering::Equal => {
 3689                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3690                                Ordering::Less => i += 1,
 3691                                Ordering::Equal => break,
 3692                                Ordering::Greater => break,
 3693                            }
 3694                        }
 3695                    }
 3696                }
 3697                this.autoclose_regions.insert(
 3698                    i,
 3699                    AutocloseRegion {
 3700                        selection_id,
 3701                        range: start..end,
 3702                        pair,
 3703                    },
 3704                );
 3705            }
 3706
 3707            let had_active_inline_completion = this.has_active_inline_completion();
 3708            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3709                s.select(new_selections)
 3710            });
 3711
 3712            if !bracket_inserted {
 3713                if let Some(on_type_format_task) =
 3714                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3715                {
 3716                    on_type_format_task.detach_and_log_err(cx);
 3717                }
 3718            }
 3719
 3720            let editor_settings = EditorSettings::get_global(cx);
 3721            if bracket_inserted
 3722                && (editor_settings.auto_signature_help
 3723                    || editor_settings.show_signature_help_after_edits)
 3724            {
 3725                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3726            }
 3727
 3728            let trigger_in_words =
 3729                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3730            if this.hard_wrap.is_some() {
 3731                let latest: Range<Point> = this.selections.newest(cx).range();
 3732                if latest.is_empty()
 3733                    && this
 3734                        .buffer()
 3735                        .read(cx)
 3736                        .snapshot(cx)
 3737                        .line_len(MultiBufferRow(latest.start.row))
 3738                        == latest.start.column
 3739                {
 3740                    this.rewrap_impl(
 3741                        RewrapOptions {
 3742                            override_language_settings: true,
 3743                            preserve_existing_whitespace: true,
 3744                        },
 3745                        cx,
 3746                    )
 3747                }
 3748            }
 3749            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3750            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3751            this.refresh_inline_completion(true, false, window, cx);
 3752            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3753        });
 3754    }
 3755
 3756    fn find_possible_emoji_shortcode_at_position(
 3757        snapshot: &MultiBufferSnapshot,
 3758        position: Point,
 3759    ) -> Option<String> {
 3760        let mut chars = Vec::new();
 3761        let mut found_colon = false;
 3762        for char in snapshot.reversed_chars_at(position).take(100) {
 3763            // Found a possible emoji shortcode in the middle of the buffer
 3764            if found_colon {
 3765                if char.is_whitespace() {
 3766                    chars.reverse();
 3767                    return Some(chars.iter().collect());
 3768                }
 3769                // If the previous character is not a whitespace, we are in the middle of a word
 3770                // and we only want to complete the shortcode if the word is made up of other emojis
 3771                let mut containing_word = String::new();
 3772                for ch in snapshot
 3773                    .reversed_chars_at(position)
 3774                    .skip(chars.len() + 1)
 3775                    .take(100)
 3776                {
 3777                    if ch.is_whitespace() {
 3778                        break;
 3779                    }
 3780                    containing_word.push(ch);
 3781                }
 3782                let containing_word = containing_word.chars().rev().collect::<String>();
 3783                if util::word_consists_of_emojis(containing_word.as_str()) {
 3784                    chars.reverse();
 3785                    return Some(chars.iter().collect());
 3786                }
 3787            }
 3788
 3789            if char.is_whitespace() || !char.is_ascii() {
 3790                return None;
 3791            }
 3792            if char == ':' {
 3793                found_colon = true;
 3794            } else {
 3795                chars.push(char);
 3796            }
 3797        }
 3798        // Found a possible emoji shortcode at the beginning of the buffer
 3799        chars.reverse();
 3800        Some(chars.iter().collect())
 3801    }
 3802
 3803    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3804        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3805        self.transact(window, cx, |this, window, cx| {
 3806            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3807                let selections = this.selections.all::<usize>(cx);
 3808                let multi_buffer = this.buffer.read(cx);
 3809                let buffer = multi_buffer.snapshot(cx);
 3810                selections
 3811                    .iter()
 3812                    .map(|selection| {
 3813                        let start_point = selection.start.to_point(&buffer);
 3814                        let mut indent =
 3815                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3816                        indent.len = cmp::min(indent.len, start_point.column);
 3817                        let start = selection.start;
 3818                        let end = selection.end;
 3819                        let selection_is_empty = start == end;
 3820                        let language_scope = buffer.language_scope_at(start);
 3821                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3822                            &language_scope
 3823                        {
 3824                            let insert_extra_newline =
 3825                                insert_extra_newline_brackets(&buffer, start..end, language)
 3826                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3827
 3828                            // Comment extension on newline is allowed only for cursor selections
 3829                            let comment_delimiter = maybe!({
 3830                                if !selection_is_empty {
 3831                                    return None;
 3832                                }
 3833
 3834                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3835                                    return None;
 3836                                }
 3837
 3838                                let delimiters = language.line_comment_prefixes();
 3839                                let max_len_of_delimiter =
 3840                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3841                                let (snapshot, range) =
 3842                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3843
 3844                                let mut index_of_first_non_whitespace = 0;
 3845                                let comment_candidate = snapshot
 3846                                    .chars_for_range(range)
 3847                                    .skip_while(|c| {
 3848                                        let should_skip = c.is_whitespace();
 3849                                        if should_skip {
 3850                                            index_of_first_non_whitespace += 1;
 3851                                        }
 3852                                        should_skip
 3853                                    })
 3854                                    .take(max_len_of_delimiter)
 3855                                    .collect::<String>();
 3856                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3857                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3858                                })?;
 3859                                let cursor_is_placed_after_comment_marker =
 3860                                    index_of_first_non_whitespace + comment_prefix.len()
 3861                                        <= start_point.column as usize;
 3862                                if cursor_is_placed_after_comment_marker {
 3863                                    Some(comment_prefix.clone())
 3864                                } else {
 3865                                    None
 3866                                }
 3867                            });
 3868                            (comment_delimiter, insert_extra_newline)
 3869                        } else {
 3870                            (None, false)
 3871                        };
 3872
 3873                        let capacity_for_delimiter = comment_delimiter
 3874                            .as_deref()
 3875                            .map(str::len)
 3876                            .unwrap_or_default();
 3877                        let mut new_text =
 3878                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3879                        new_text.push('\n');
 3880                        new_text.extend(indent.chars());
 3881                        if let Some(delimiter) = &comment_delimiter {
 3882                            new_text.push_str(delimiter);
 3883                        }
 3884                        if insert_extra_newline {
 3885                            new_text = new_text.repeat(2);
 3886                        }
 3887
 3888                        let anchor = buffer.anchor_after(end);
 3889                        let new_selection = selection.map(|_| anchor);
 3890                        (
 3891                            (start..end, new_text),
 3892                            (insert_extra_newline, new_selection),
 3893                        )
 3894                    })
 3895                    .unzip()
 3896            };
 3897
 3898            this.edit_with_autoindent(edits, cx);
 3899            let buffer = this.buffer.read(cx).snapshot(cx);
 3900            let new_selections = selection_fixup_info
 3901                .into_iter()
 3902                .map(|(extra_newline_inserted, new_selection)| {
 3903                    let mut cursor = new_selection.end.to_point(&buffer);
 3904                    if extra_newline_inserted {
 3905                        cursor.row -= 1;
 3906                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3907                    }
 3908                    new_selection.map(|_| cursor)
 3909                })
 3910                .collect();
 3911
 3912            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3913                s.select(new_selections)
 3914            });
 3915            this.refresh_inline_completion(true, false, window, cx);
 3916        });
 3917    }
 3918
 3919    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 3920        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3921
 3922        let buffer = self.buffer.read(cx);
 3923        let snapshot = buffer.snapshot(cx);
 3924
 3925        let mut edits = Vec::new();
 3926        let mut rows = Vec::new();
 3927
 3928        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3929            let cursor = selection.head();
 3930            let row = cursor.row;
 3931
 3932            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3933
 3934            let newline = "\n".to_string();
 3935            edits.push((start_of_line..start_of_line, newline));
 3936
 3937            rows.push(row + rows_inserted as u32);
 3938        }
 3939
 3940        self.transact(window, cx, |editor, window, cx| {
 3941            editor.edit(edits, cx);
 3942
 3943            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3944                let mut index = 0;
 3945                s.move_cursors_with(|map, _, _| {
 3946                    let row = rows[index];
 3947                    index += 1;
 3948
 3949                    let point = Point::new(row, 0);
 3950                    let boundary = map.next_line_boundary(point).1;
 3951                    let clipped = map.clip_point(boundary, Bias::Left);
 3952
 3953                    (clipped, SelectionGoal::None)
 3954                });
 3955            });
 3956
 3957            let mut indent_edits = Vec::new();
 3958            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3959            for row in rows {
 3960                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3961                for (row, indent) in indents {
 3962                    if indent.len == 0 {
 3963                        continue;
 3964                    }
 3965
 3966                    let text = match indent.kind {
 3967                        IndentKind::Space => " ".repeat(indent.len as usize),
 3968                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3969                    };
 3970                    let point = Point::new(row.0, 0);
 3971                    indent_edits.push((point..point, text));
 3972                }
 3973            }
 3974            editor.edit(indent_edits, cx);
 3975        });
 3976    }
 3977
 3978    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 3979        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3980
 3981        let buffer = self.buffer.read(cx);
 3982        let snapshot = buffer.snapshot(cx);
 3983
 3984        let mut edits = Vec::new();
 3985        let mut rows = Vec::new();
 3986        let mut rows_inserted = 0;
 3987
 3988        for selection in self.selections.all_adjusted(cx) {
 3989            let cursor = selection.head();
 3990            let row = cursor.row;
 3991
 3992            let point = Point::new(row + 1, 0);
 3993            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3994
 3995            let newline = "\n".to_string();
 3996            edits.push((start_of_line..start_of_line, newline));
 3997
 3998            rows_inserted += 1;
 3999            rows.push(row + rows_inserted);
 4000        }
 4001
 4002        self.transact(window, cx, |editor, window, cx| {
 4003            editor.edit(edits, cx);
 4004
 4005            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4006                let mut index = 0;
 4007                s.move_cursors_with(|map, _, _| {
 4008                    let row = rows[index];
 4009                    index += 1;
 4010
 4011                    let point = Point::new(row, 0);
 4012                    let boundary = map.next_line_boundary(point).1;
 4013                    let clipped = map.clip_point(boundary, Bias::Left);
 4014
 4015                    (clipped, SelectionGoal::None)
 4016                });
 4017            });
 4018
 4019            let mut indent_edits = Vec::new();
 4020            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4021            for row in rows {
 4022                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4023                for (row, indent) in indents {
 4024                    if indent.len == 0 {
 4025                        continue;
 4026                    }
 4027
 4028                    let text = match indent.kind {
 4029                        IndentKind::Space => " ".repeat(indent.len as usize),
 4030                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4031                    };
 4032                    let point = Point::new(row.0, 0);
 4033                    indent_edits.push((point..point, text));
 4034                }
 4035            }
 4036            editor.edit(indent_edits, cx);
 4037        });
 4038    }
 4039
 4040    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4041        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4042            original_indent_columns: Vec::new(),
 4043        });
 4044        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4045    }
 4046
 4047    fn insert_with_autoindent_mode(
 4048        &mut self,
 4049        text: &str,
 4050        autoindent_mode: Option<AutoindentMode>,
 4051        window: &mut Window,
 4052        cx: &mut Context<Self>,
 4053    ) {
 4054        if self.read_only(cx) {
 4055            return;
 4056        }
 4057
 4058        let text: Arc<str> = text.into();
 4059        self.transact(window, cx, |this, window, cx| {
 4060            let old_selections = this.selections.all_adjusted(cx);
 4061            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4062                let anchors = {
 4063                    let snapshot = buffer.read(cx);
 4064                    old_selections
 4065                        .iter()
 4066                        .map(|s| {
 4067                            let anchor = snapshot.anchor_after(s.head());
 4068                            s.map(|_| anchor)
 4069                        })
 4070                        .collect::<Vec<_>>()
 4071                };
 4072                buffer.edit(
 4073                    old_selections
 4074                        .iter()
 4075                        .map(|s| (s.start..s.end, text.clone())),
 4076                    autoindent_mode,
 4077                    cx,
 4078                );
 4079                anchors
 4080            });
 4081
 4082            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4083                s.select_anchors(selection_anchors);
 4084            });
 4085
 4086            cx.notify();
 4087        });
 4088    }
 4089
 4090    fn trigger_completion_on_input(
 4091        &mut self,
 4092        text: &str,
 4093        trigger_in_words: bool,
 4094        window: &mut Window,
 4095        cx: &mut Context<Self>,
 4096    ) {
 4097        let ignore_completion_provider = self
 4098            .context_menu
 4099            .borrow()
 4100            .as_ref()
 4101            .map(|menu| match menu {
 4102                CodeContextMenu::Completions(completions_menu) => {
 4103                    completions_menu.ignore_completion_provider
 4104                }
 4105                CodeContextMenu::CodeActions(_) => false,
 4106            })
 4107            .unwrap_or(false);
 4108
 4109        if ignore_completion_provider {
 4110            self.show_word_completions(&ShowWordCompletions, window, cx);
 4111        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4112            self.show_completions(
 4113                &ShowCompletions {
 4114                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4115                },
 4116                window,
 4117                cx,
 4118            );
 4119        } else {
 4120            self.hide_context_menu(window, cx);
 4121        }
 4122    }
 4123
 4124    fn is_completion_trigger(
 4125        &self,
 4126        text: &str,
 4127        trigger_in_words: bool,
 4128        cx: &mut Context<Self>,
 4129    ) -> bool {
 4130        let position = self.selections.newest_anchor().head();
 4131        let multibuffer = self.buffer.read(cx);
 4132        let Some(buffer) = position
 4133            .buffer_id
 4134            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4135        else {
 4136            return false;
 4137        };
 4138
 4139        if let Some(completion_provider) = &self.completion_provider {
 4140            completion_provider.is_completion_trigger(
 4141                &buffer,
 4142                position.text_anchor,
 4143                text,
 4144                trigger_in_words,
 4145                cx,
 4146            )
 4147        } else {
 4148            false
 4149        }
 4150    }
 4151
 4152    /// If any empty selections is touching the start of its innermost containing autoclose
 4153    /// region, expand it to select the brackets.
 4154    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4155        let selections = self.selections.all::<usize>(cx);
 4156        let buffer = self.buffer.read(cx).read(cx);
 4157        let new_selections = self
 4158            .selections_with_autoclose_regions(selections, &buffer)
 4159            .map(|(mut selection, region)| {
 4160                if !selection.is_empty() {
 4161                    return selection;
 4162                }
 4163
 4164                if let Some(region) = region {
 4165                    let mut range = region.range.to_offset(&buffer);
 4166                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4167                        range.start -= region.pair.start.len();
 4168                        if buffer.contains_str_at(range.start, &region.pair.start)
 4169                            && buffer.contains_str_at(range.end, &region.pair.end)
 4170                        {
 4171                            range.end += region.pair.end.len();
 4172                            selection.start = range.start;
 4173                            selection.end = range.end;
 4174
 4175                            return selection;
 4176                        }
 4177                    }
 4178                }
 4179
 4180                let always_treat_brackets_as_autoclosed = buffer
 4181                    .language_settings_at(selection.start, cx)
 4182                    .always_treat_brackets_as_autoclosed;
 4183
 4184                if !always_treat_brackets_as_autoclosed {
 4185                    return selection;
 4186                }
 4187
 4188                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4189                    for (pair, enabled) in scope.brackets() {
 4190                        if !enabled || !pair.close {
 4191                            continue;
 4192                        }
 4193
 4194                        if buffer.contains_str_at(selection.start, &pair.end) {
 4195                            let pair_start_len = pair.start.len();
 4196                            if buffer.contains_str_at(
 4197                                selection.start.saturating_sub(pair_start_len),
 4198                                &pair.start,
 4199                            ) {
 4200                                selection.start -= pair_start_len;
 4201                                selection.end += pair.end.len();
 4202
 4203                                return selection;
 4204                            }
 4205                        }
 4206                    }
 4207                }
 4208
 4209                selection
 4210            })
 4211            .collect();
 4212
 4213        drop(buffer);
 4214        self.change_selections(None, window, cx, |selections| {
 4215            selections.select(new_selections)
 4216        });
 4217    }
 4218
 4219    /// Iterate the given selections, and for each one, find the smallest surrounding
 4220    /// autoclose region. This uses the ordering of the selections and the autoclose
 4221    /// regions to avoid repeated comparisons.
 4222    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4223        &'a self,
 4224        selections: impl IntoIterator<Item = Selection<D>>,
 4225        buffer: &'a MultiBufferSnapshot,
 4226    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4227        let mut i = 0;
 4228        let mut regions = self.autoclose_regions.as_slice();
 4229        selections.into_iter().map(move |selection| {
 4230            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4231
 4232            let mut enclosing = None;
 4233            while let Some(pair_state) = regions.get(i) {
 4234                if pair_state.range.end.to_offset(buffer) < range.start {
 4235                    regions = &regions[i + 1..];
 4236                    i = 0;
 4237                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4238                    break;
 4239                } else {
 4240                    if pair_state.selection_id == selection.id {
 4241                        enclosing = Some(pair_state);
 4242                    }
 4243                    i += 1;
 4244                }
 4245            }
 4246
 4247            (selection, enclosing)
 4248        })
 4249    }
 4250
 4251    /// Remove any autoclose regions that no longer contain their selection.
 4252    fn invalidate_autoclose_regions(
 4253        &mut self,
 4254        mut selections: &[Selection<Anchor>],
 4255        buffer: &MultiBufferSnapshot,
 4256    ) {
 4257        self.autoclose_regions.retain(|state| {
 4258            let mut i = 0;
 4259            while let Some(selection) = selections.get(i) {
 4260                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4261                    selections = &selections[1..];
 4262                    continue;
 4263                }
 4264                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4265                    break;
 4266                }
 4267                if selection.id == state.selection_id {
 4268                    return true;
 4269                } else {
 4270                    i += 1;
 4271                }
 4272            }
 4273            false
 4274        });
 4275    }
 4276
 4277    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4278        let offset = position.to_offset(buffer);
 4279        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4280        if offset > word_range.start && kind == Some(CharKind::Word) {
 4281            Some(
 4282                buffer
 4283                    .text_for_range(word_range.start..offset)
 4284                    .collect::<String>(),
 4285            )
 4286        } else {
 4287            None
 4288        }
 4289    }
 4290
 4291    pub fn toggle_inline_values(
 4292        &mut self,
 4293        _: &ToggleInlineValues,
 4294        _: &mut Window,
 4295        cx: &mut Context<Self>,
 4296    ) {
 4297        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4298
 4299        self.refresh_inline_values(cx);
 4300    }
 4301
 4302    pub fn toggle_inlay_hints(
 4303        &mut self,
 4304        _: &ToggleInlayHints,
 4305        _: &mut Window,
 4306        cx: &mut Context<Self>,
 4307    ) {
 4308        self.refresh_inlay_hints(
 4309            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4310            cx,
 4311        );
 4312    }
 4313
 4314    pub fn inlay_hints_enabled(&self) -> bool {
 4315        self.inlay_hint_cache.enabled
 4316    }
 4317
 4318    pub fn inline_values_enabled(&self) -> bool {
 4319        self.inline_value_cache.enabled
 4320    }
 4321
 4322    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4323        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4324            return;
 4325        }
 4326
 4327        let reason_description = reason.description();
 4328        let ignore_debounce = matches!(
 4329            reason,
 4330            InlayHintRefreshReason::SettingsChange(_)
 4331                | InlayHintRefreshReason::Toggle(_)
 4332                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4333                | InlayHintRefreshReason::ModifiersChanged(_)
 4334        );
 4335        let (invalidate_cache, required_languages) = match reason {
 4336            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4337                match self.inlay_hint_cache.modifiers_override(enabled) {
 4338                    Some(enabled) => {
 4339                        if enabled {
 4340                            (InvalidationStrategy::RefreshRequested, None)
 4341                        } else {
 4342                            self.splice_inlays(
 4343                                &self
 4344                                    .visible_inlay_hints(cx)
 4345                                    .iter()
 4346                                    .map(|inlay| inlay.id)
 4347                                    .collect::<Vec<InlayId>>(),
 4348                                Vec::new(),
 4349                                cx,
 4350                            );
 4351                            return;
 4352                        }
 4353                    }
 4354                    None => return,
 4355                }
 4356            }
 4357            InlayHintRefreshReason::Toggle(enabled) => {
 4358                if self.inlay_hint_cache.toggle(enabled) {
 4359                    if enabled {
 4360                        (InvalidationStrategy::RefreshRequested, None)
 4361                    } else {
 4362                        self.splice_inlays(
 4363                            &self
 4364                                .visible_inlay_hints(cx)
 4365                                .iter()
 4366                                .map(|inlay| inlay.id)
 4367                                .collect::<Vec<InlayId>>(),
 4368                            Vec::new(),
 4369                            cx,
 4370                        );
 4371                        return;
 4372                    }
 4373                } else {
 4374                    return;
 4375                }
 4376            }
 4377            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4378                match self.inlay_hint_cache.update_settings(
 4379                    &self.buffer,
 4380                    new_settings,
 4381                    self.visible_inlay_hints(cx),
 4382                    cx,
 4383                ) {
 4384                    ControlFlow::Break(Some(InlaySplice {
 4385                        to_remove,
 4386                        to_insert,
 4387                    })) => {
 4388                        self.splice_inlays(&to_remove, to_insert, cx);
 4389                        return;
 4390                    }
 4391                    ControlFlow::Break(None) => return,
 4392                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4393                }
 4394            }
 4395            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4396                if let Some(InlaySplice {
 4397                    to_remove,
 4398                    to_insert,
 4399                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4400                {
 4401                    self.splice_inlays(&to_remove, to_insert, cx);
 4402                }
 4403                self.display_map.update(cx, |display_map, _| {
 4404                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4405                });
 4406                return;
 4407            }
 4408            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4409            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4410                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4411            }
 4412            InlayHintRefreshReason::RefreshRequested => {
 4413                (InvalidationStrategy::RefreshRequested, None)
 4414            }
 4415        };
 4416
 4417        if let Some(InlaySplice {
 4418            to_remove,
 4419            to_insert,
 4420        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4421            reason_description,
 4422            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4423            invalidate_cache,
 4424            ignore_debounce,
 4425            cx,
 4426        ) {
 4427            self.splice_inlays(&to_remove, to_insert, cx);
 4428        }
 4429    }
 4430
 4431    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4432        self.display_map
 4433            .read(cx)
 4434            .current_inlays()
 4435            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4436            .cloned()
 4437            .collect()
 4438    }
 4439
 4440    pub fn excerpts_for_inlay_hints_query(
 4441        &self,
 4442        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4443        cx: &mut Context<Editor>,
 4444    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4445        let Some(project) = self.project.as_ref() else {
 4446            return HashMap::default();
 4447        };
 4448        let project = project.read(cx);
 4449        let multi_buffer = self.buffer().read(cx);
 4450        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4451        let multi_buffer_visible_start = self
 4452            .scroll_manager
 4453            .anchor()
 4454            .anchor
 4455            .to_point(&multi_buffer_snapshot);
 4456        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4457            multi_buffer_visible_start
 4458                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4459            Bias::Left,
 4460        );
 4461        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4462        multi_buffer_snapshot
 4463            .range_to_buffer_ranges(multi_buffer_visible_range)
 4464            .into_iter()
 4465            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4466            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4467                let buffer_file = project::File::from_dyn(buffer.file())?;
 4468                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4469                let worktree_entry = buffer_worktree
 4470                    .read(cx)
 4471                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4472                if worktree_entry.is_ignored {
 4473                    return None;
 4474                }
 4475
 4476                let language = buffer.language()?;
 4477                if let Some(restrict_to_languages) = restrict_to_languages {
 4478                    if !restrict_to_languages.contains(language) {
 4479                        return None;
 4480                    }
 4481                }
 4482                Some((
 4483                    excerpt_id,
 4484                    (
 4485                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4486                        buffer.version().clone(),
 4487                        excerpt_visible_range,
 4488                    ),
 4489                ))
 4490            })
 4491            .collect()
 4492    }
 4493
 4494    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4495        TextLayoutDetails {
 4496            text_system: window.text_system().clone(),
 4497            editor_style: self.style.clone().unwrap(),
 4498            rem_size: window.rem_size(),
 4499            scroll_anchor: self.scroll_manager.anchor(),
 4500            visible_rows: self.visible_line_count(),
 4501            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4502        }
 4503    }
 4504
 4505    pub fn splice_inlays(
 4506        &self,
 4507        to_remove: &[InlayId],
 4508        to_insert: Vec<Inlay>,
 4509        cx: &mut Context<Self>,
 4510    ) {
 4511        self.display_map.update(cx, |display_map, cx| {
 4512            display_map.splice_inlays(to_remove, to_insert, cx)
 4513        });
 4514        cx.notify();
 4515    }
 4516
 4517    fn trigger_on_type_formatting(
 4518        &self,
 4519        input: String,
 4520        window: &mut Window,
 4521        cx: &mut Context<Self>,
 4522    ) -> Option<Task<Result<()>>> {
 4523        if input.len() != 1 {
 4524            return None;
 4525        }
 4526
 4527        let project = self.project.as_ref()?;
 4528        let position = self.selections.newest_anchor().head();
 4529        let (buffer, buffer_position) = self
 4530            .buffer
 4531            .read(cx)
 4532            .text_anchor_for_position(position, cx)?;
 4533
 4534        let settings = language_settings::language_settings(
 4535            buffer
 4536                .read(cx)
 4537                .language_at(buffer_position)
 4538                .map(|l| l.name()),
 4539            buffer.read(cx).file(),
 4540            cx,
 4541        );
 4542        if !settings.use_on_type_format {
 4543            return None;
 4544        }
 4545
 4546        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4547        // hence we do LSP request & edit on host side only — add formats to host's history.
 4548        let push_to_lsp_host_history = true;
 4549        // If this is not the host, append its history with new edits.
 4550        let push_to_client_history = project.read(cx).is_via_collab();
 4551
 4552        let on_type_formatting = project.update(cx, |project, cx| {
 4553            project.on_type_format(
 4554                buffer.clone(),
 4555                buffer_position,
 4556                input,
 4557                push_to_lsp_host_history,
 4558                cx,
 4559            )
 4560        });
 4561        Some(cx.spawn_in(window, async move |editor, cx| {
 4562            if let Some(transaction) = on_type_formatting.await? {
 4563                if push_to_client_history {
 4564                    buffer
 4565                        .update(cx, |buffer, _| {
 4566                            buffer.push_transaction(transaction, Instant::now());
 4567                            buffer.finalize_last_transaction();
 4568                        })
 4569                        .ok();
 4570                }
 4571                editor.update(cx, |editor, cx| {
 4572                    editor.refresh_document_highlights(cx);
 4573                })?;
 4574            }
 4575            Ok(())
 4576        }))
 4577    }
 4578
 4579    pub fn show_word_completions(
 4580        &mut self,
 4581        _: &ShowWordCompletions,
 4582        window: &mut Window,
 4583        cx: &mut Context<Self>,
 4584    ) {
 4585        self.open_completions_menu(true, None, window, cx);
 4586    }
 4587
 4588    pub fn show_completions(
 4589        &mut self,
 4590        options: &ShowCompletions,
 4591        window: &mut Window,
 4592        cx: &mut Context<Self>,
 4593    ) {
 4594        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4595    }
 4596
 4597    fn open_completions_menu(
 4598        &mut self,
 4599        ignore_completion_provider: bool,
 4600        trigger: Option<&str>,
 4601        window: &mut Window,
 4602        cx: &mut Context<Self>,
 4603    ) {
 4604        if self.pending_rename.is_some() {
 4605            return;
 4606        }
 4607        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4608            return;
 4609        }
 4610
 4611        let position = self.selections.newest_anchor().head();
 4612        if position.diff_base_anchor.is_some() {
 4613            return;
 4614        }
 4615        let (buffer, buffer_position) =
 4616            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4617                output
 4618            } else {
 4619                return;
 4620            };
 4621        let buffer_snapshot = buffer.read(cx).snapshot();
 4622        let show_completion_documentation = buffer_snapshot
 4623            .settings_at(buffer_position, cx)
 4624            .show_completion_documentation;
 4625
 4626        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4627
 4628        let trigger_kind = match trigger {
 4629            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4630                CompletionTriggerKind::TRIGGER_CHARACTER
 4631            }
 4632            _ => CompletionTriggerKind::INVOKED,
 4633        };
 4634        let completion_context = CompletionContext {
 4635            trigger_character: trigger.and_then(|trigger| {
 4636                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4637                    Some(String::from(trigger))
 4638                } else {
 4639                    None
 4640                }
 4641            }),
 4642            trigger_kind,
 4643        };
 4644
 4645        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4646        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4647            let word_to_exclude = buffer_snapshot
 4648                .text_for_range(old_range.clone())
 4649                .collect::<String>();
 4650            (
 4651                buffer_snapshot.anchor_before(old_range.start)
 4652                    ..buffer_snapshot.anchor_after(old_range.end),
 4653                Some(word_to_exclude),
 4654            )
 4655        } else {
 4656            (buffer_position..buffer_position, None)
 4657        };
 4658
 4659        let completion_settings = language_settings(
 4660            buffer_snapshot
 4661                .language_at(buffer_position)
 4662                .map(|language| language.name()),
 4663            buffer_snapshot.file(),
 4664            cx,
 4665        )
 4666        .completions;
 4667
 4668        // The document can be large, so stay in reasonable bounds when searching for words,
 4669        // otherwise completion pop-up might be slow to appear.
 4670        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4671        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4672        let min_word_search = buffer_snapshot.clip_point(
 4673            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4674            Bias::Left,
 4675        );
 4676        let max_word_search = buffer_snapshot.clip_point(
 4677            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4678            Bias::Right,
 4679        );
 4680        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4681            ..buffer_snapshot.point_to_offset(max_word_search);
 4682
 4683        let provider = self
 4684            .completion_provider
 4685            .as_ref()
 4686            .filter(|_| !ignore_completion_provider);
 4687        let skip_digits = query
 4688            .as_ref()
 4689            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4690
 4691        let (mut words, provided_completions) = match provider {
 4692            Some(provider) => {
 4693                let completions = provider.completions(
 4694                    position.excerpt_id,
 4695                    &buffer,
 4696                    buffer_position,
 4697                    completion_context,
 4698                    window,
 4699                    cx,
 4700                );
 4701
 4702                let words = match completion_settings.words {
 4703                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4704                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4705                        .background_spawn(async move {
 4706                            buffer_snapshot.words_in_range(WordsQuery {
 4707                                fuzzy_contents: None,
 4708                                range: word_search_range,
 4709                                skip_digits,
 4710                            })
 4711                        }),
 4712                };
 4713
 4714                (words, completions)
 4715            }
 4716            None => (
 4717                cx.background_spawn(async move {
 4718                    buffer_snapshot.words_in_range(WordsQuery {
 4719                        fuzzy_contents: None,
 4720                        range: word_search_range,
 4721                        skip_digits,
 4722                    })
 4723                }),
 4724                Task::ready(Ok(None)),
 4725            ),
 4726        };
 4727
 4728        let sort_completions = provider
 4729            .as_ref()
 4730            .map_or(false, |provider| provider.sort_completions());
 4731
 4732        let filter_completions = provider
 4733            .as_ref()
 4734            .map_or(true, |provider| provider.filter_completions());
 4735
 4736        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 4737
 4738        let id = post_inc(&mut self.next_completion_id);
 4739        let task = cx.spawn_in(window, async move |editor, cx| {
 4740            async move {
 4741                editor.update(cx, |this, _| {
 4742                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 4743                })?;
 4744
 4745                let mut completions = Vec::new();
 4746                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 4747                    completions.extend(provided_completions);
 4748                    if completion_settings.words == WordsCompletionMode::Fallback {
 4749                        words = Task::ready(BTreeMap::default());
 4750                    }
 4751                }
 4752
 4753                let mut words = words.await;
 4754                if let Some(word_to_exclude) = &word_to_exclude {
 4755                    words.remove(word_to_exclude);
 4756                }
 4757                for lsp_completion in &completions {
 4758                    words.remove(&lsp_completion.new_text);
 4759                }
 4760                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 4761                    replace_range: old_range.clone(),
 4762                    new_text: word.clone(),
 4763                    label: CodeLabel::plain(word, None),
 4764                    icon_path: None,
 4765                    documentation: None,
 4766                    source: CompletionSource::BufferWord {
 4767                        word_range,
 4768                        resolved: false,
 4769                    },
 4770                    insert_text_mode: Some(InsertTextMode::AS_IS),
 4771                    confirm: None,
 4772                }));
 4773
 4774                let menu = if completions.is_empty() {
 4775                    None
 4776                } else {
 4777                    let mut menu = CompletionsMenu::new(
 4778                        id,
 4779                        sort_completions,
 4780                        show_completion_documentation,
 4781                        ignore_completion_provider,
 4782                        position,
 4783                        buffer.clone(),
 4784                        completions.into(),
 4785                        snippet_sort_order,
 4786                    );
 4787
 4788                    menu.filter(
 4789                        if filter_completions {
 4790                            query.as_deref()
 4791                        } else {
 4792                            None
 4793                        },
 4794                        cx.background_executor().clone(),
 4795                    )
 4796                    .await;
 4797
 4798                    menu.visible().then_some(menu)
 4799                };
 4800
 4801                editor.update_in(cx, |editor, window, cx| {
 4802                    match editor.context_menu.borrow().as_ref() {
 4803                        None => {}
 4804                        Some(CodeContextMenu::Completions(prev_menu)) => {
 4805                            if prev_menu.id > id {
 4806                                return;
 4807                            }
 4808                        }
 4809                        _ => return,
 4810                    }
 4811
 4812                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 4813                        let mut menu = menu.unwrap();
 4814                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 4815
 4816                        *editor.context_menu.borrow_mut() =
 4817                            Some(CodeContextMenu::Completions(menu));
 4818
 4819                        if editor.show_edit_predictions_in_menu() {
 4820                            editor.update_visible_inline_completion(window, cx);
 4821                        } else {
 4822                            editor.discard_inline_completion(false, cx);
 4823                        }
 4824
 4825                        cx.notify();
 4826                    } else if editor.completion_tasks.len() <= 1 {
 4827                        // If there are no more completion tasks and the last menu was
 4828                        // empty, we should hide it.
 4829                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 4830                        // If it was already hidden and we don't show inline
 4831                        // completions in the menu, we should also show the
 4832                        // inline-completion when available.
 4833                        if was_hidden && editor.show_edit_predictions_in_menu() {
 4834                            editor.update_visible_inline_completion(window, cx);
 4835                        }
 4836                    }
 4837                })?;
 4838
 4839                anyhow::Ok(())
 4840            }
 4841            .log_err()
 4842            .await
 4843        });
 4844
 4845        self.completion_tasks.push((id, task));
 4846    }
 4847
 4848    #[cfg(feature = "test-support")]
 4849    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 4850        let menu = self.context_menu.borrow();
 4851        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 4852            let completions = menu.completions.borrow();
 4853            Some(completions.to_vec())
 4854        } else {
 4855            None
 4856        }
 4857    }
 4858
 4859    pub fn confirm_completion(
 4860        &mut self,
 4861        action: &ConfirmCompletion,
 4862        window: &mut Window,
 4863        cx: &mut Context<Self>,
 4864    ) -> Option<Task<Result<()>>> {
 4865        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4866        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 4867    }
 4868
 4869    pub fn confirm_completion_insert(
 4870        &mut self,
 4871        _: &ConfirmCompletionInsert,
 4872        window: &mut Window,
 4873        cx: &mut Context<Self>,
 4874    ) -> Option<Task<Result<()>>> {
 4875        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4876        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 4877    }
 4878
 4879    pub fn confirm_completion_replace(
 4880        &mut self,
 4881        _: &ConfirmCompletionReplace,
 4882        window: &mut Window,
 4883        cx: &mut Context<Self>,
 4884    ) -> Option<Task<Result<()>>> {
 4885        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4886        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 4887    }
 4888
 4889    pub fn compose_completion(
 4890        &mut self,
 4891        action: &ComposeCompletion,
 4892        window: &mut Window,
 4893        cx: &mut Context<Self>,
 4894    ) -> Option<Task<Result<()>>> {
 4895        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4896        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 4897    }
 4898
 4899    fn do_completion(
 4900        &mut self,
 4901        item_ix: Option<usize>,
 4902        intent: CompletionIntent,
 4903        window: &mut Window,
 4904        cx: &mut Context<Editor>,
 4905    ) -> Option<Task<Result<()>>> {
 4906        use language::ToOffset as _;
 4907
 4908        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 4909        else {
 4910            return None;
 4911        };
 4912
 4913        let candidate_id = {
 4914            let entries = completions_menu.entries.borrow();
 4915            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 4916            if self.show_edit_predictions_in_menu() {
 4917                self.discard_inline_completion(true, cx);
 4918            }
 4919            mat.candidate_id
 4920        };
 4921
 4922        let buffer_handle = completions_menu.buffer;
 4923        let completion = completions_menu
 4924            .completions
 4925            .borrow()
 4926            .get(candidate_id)?
 4927            .clone();
 4928        cx.stop_propagation();
 4929
 4930        let snippet;
 4931        let new_text;
 4932        if completion.is_snippet() {
 4933            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 4934            new_text = snippet.as_ref().unwrap().text.clone();
 4935        } else {
 4936            snippet = None;
 4937            new_text = completion.new_text.clone();
 4938        };
 4939
 4940        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 4941        let buffer = buffer_handle.read(cx);
 4942        let snapshot = self.buffer.read(cx).snapshot(cx);
 4943        let replace_range_multibuffer = {
 4944            let excerpt = snapshot
 4945                .excerpt_containing(self.selections.newest_anchor().range())
 4946                .unwrap();
 4947            let multibuffer_anchor = snapshot
 4948                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 4949                .unwrap()
 4950                ..snapshot
 4951                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 4952                    .unwrap();
 4953            multibuffer_anchor.start.to_offset(&snapshot)
 4954                ..multibuffer_anchor.end.to_offset(&snapshot)
 4955        };
 4956        let newest_anchor = self.selections.newest_anchor();
 4957        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 4958            return None;
 4959        }
 4960
 4961        let old_text = buffer
 4962            .text_for_range(replace_range.clone())
 4963            .collect::<String>();
 4964        let lookbehind = newest_anchor
 4965            .start
 4966            .text_anchor
 4967            .to_offset(buffer)
 4968            .saturating_sub(replace_range.start);
 4969        let lookahead = replace_range
 4970            .end
 4971            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 4972        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 4973        let suffix = &old_text[lookbehind.min(old_text.len())..];
 4974
 4975        let selections = self.selections.all::<usize>(cx);
 4976        let mut ranges = Vec::new();
 4977        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4978
 4979        for selection in &selections {
 4980            let range = if selection.id == newest_anchor.id {
 4981                replace_range_multibuffer.clone()
 4982            } else {
 4983                let mut range = selection.range();
 4984
 4985                // if prefix is present, don't duplicate it
 4986                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 4987                    range.start = range.start.saturating_sub(lookbehind);
 4988
 4989                    // if suffix is also present, mimic the newest cursor and replace it
 4990                    if selection.id != newest_anchor.id
 4991                        && snapshot.contains_str_at(range.end, suffix)
 4992                    {
 4993                        range.end += lookahead;
 4994                    }
 4995                }
 4996                range
 4997            };
 4998
 4999            ranges.push(range);
 5000
 5001            if !self.linked_edit_ranges.is_empty() {
 5002                let start_anchor = snapshot.anchor_before(selection.head());
 5003                let end_anchor = snapshot.anchor_after(selection.tail());
 5004                if let Some(ranges) = self
 5005                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5006                {
 5007                    for (buffer, edits) in ranges {
 5008                        linked_edits
 5009                            .entry(buffer.clone())
 5010                            .or_default()
 5011                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5012                    }
 5013                }
 5014            }
 5015        }
 5016
 5017        cx.emit(EditorEvent::InputHandled {
 5018            utf16_range_to_replace: None,
 5019            text: new_text.clone().into(),
 5020        });
 5021
 5022        self.transact(window, cx, |this, window, cx| {
 5023            if let Some(mut snippet) = snippet {
 5024                snippet.text = new_text.to_string();
 5025                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5026            } else {
 5027                this.buffer.update(cx, |buffer, cx| {
 5028                    let auto_indent = match completion.insert_text_mode {
 5029                        Some(InsertTextMode::AS_IS) => None,
 5030                        _ => this.autoindent_mode.clone(),
 5031                    };
 5032                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5033                    buffer.edit(edits, auto_indent, cx);
 5034                });
 5035            }
 5036            for (buffer, edits) in linked_edits {
 5037                buffer.update(cx, |buffer, cx| {
 5038                    let snapshot = buffer.snapshot();
 5039                    let edits = edits
 5040                        .into_iter()
 5041                        .map(|(range, text)| {
 5042                            use text::ToPoint as TP;
 5043                            let end_point = TP::to_point(&range.end, &snapshot);
 5044                            let start_point = TP::to_point(&range.start, &snapshot);
 5045                            (start_point..end_point, text)
 5046                        })
 5047                        .sorted_by_key(|(range, _)| range.start);
 5048                    buffer.edit(edits, None, cx);
 5049                })
 5050            }
 5051
 5052            this.refresh_inline_completion(true, false, window, cx);
 5053        });
 5054
 5055        let show_new_completions_on_confirm = completion
 5056            .confirm
 5057            .as_ref()
 5058            .map_or(false, |confirm| confirm(intent, window, cx));
 5059        if show_new_completions_on_confirm {
 5060            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5061        }
 5062
 5063        let provider = self.completion_provider.as_ref()?;
 5064        drop(completion);
 5065        let apply_edits = provider.apply_additional_edits_for_completion(
 5066            buffer_handle,
 5067            completions_menu.completions.clone(),
 5068            candidate_id,
 5069            true,
 5070            cx,
 5071        );
 5072
 5073        let editor_settings = EditorSettings::get_global(cx);
 5074        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5075            // After the code completion is finished, users often want to know what signatures are needed.
 5076            // so we should automatically call signature_help
 5077            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5078        }
 5079
 5080        Some(cx.foreground_executor().spawn(async move {
 5081            apply_edits.await?;
 5082            Ok(())
 5083        }))
 5084    }
 5085
 5086    pub fn toggle_code_actions(
 5087        &mut self,
 5088        action: &ToggleCodeActions,
 5089        window: &mut Window,
 5090        cx: &mut Context<Self>,
 5091    ) {
 5092        let quick_launch = action.quick_launch;
 5093        let mut context_menu = self.context_menu.borrow_mut();
 5094        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5095            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5096                // Toggle if we're selecting the same one
 5097                *context_menu = None;
 5098                cx.notify();
 5099                return;
 5100            } else {
 5101                // Otherwise, clear it and start a new one
 5102                *context_menu = None;
 5103                cx.notify();
 5104            }
 5105        }
 5106        drop(context_menu);
 5107        let snapshot = self.snapshot(window, cx);
 5108        let deployed_from_indicator = action.deployed_from_indicator;
 5109        let mut task = self.code_actions_task.take();
 5110        let action = action.clone();
 5111        cx.spawn_in(window, async move |editor, cx| {
 5112            while let Some(prev_task) = task {
 5113                prev_task.await.log_err();
 5114                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5115            }
 5116
 5117            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5118                if editor.focus_handle.is_focused(window) {
 5119                    let multibuffer_point = action
 5120                        .deployed_from_indicator
 5121                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5122                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5123                    let (buffer, buffer_row) = snapshot
 5124                        .buffer_snapshot
 5125                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5126                        .and_then(|(buffer_snapshot, range)| {
 5127                            editor
 5128                                .buffer
 5129                                .read(cx)
 5130                                .buffer(buffer_snapshot.remote_id())
 5131                                .map(|buffer| (buffer, range.start.row))
 5132                        })?;
 5133                    let (_, code_actions) = editor
 5134                        .available_code_actions
 5135                        .clone()
 5136                        .and_then(|(location, code_actions)| {
 5137                            let snapshot = location.buffer.read(cx).snapshot();
 5138                            let point_range = location.range.to_point(&snapshot);
 5139                            let point_range = point_range.start.row..=point_range.end.row;
 5140                            if point_range.contains(&buffer_row) {
 5141                                Some((location, code_actions))
 5142                            } else {
 5143                                None
 5144                            }
 5145                        })
 5146                        .unzip();
 5147                    let buffer_id = buffer.read(cx).remote_id();
 5148                    let tasks = editor
 5149                        .tasks
 5150                        .get(&(buffer_id, buffer_row))
 5151                        .map(|t| Arc::new(t.to_owned()));
 5152                    if tasks.is_none() && code_actions.is_none() {
 5153                        return None;
 5154                    }
 5155
 5156                    editor.completion_tasks.clear();
 5157                    editor.discard_inline_completion(false, cx);
 5158                    let task_context =
 5159                        tasks
 5160                            .as_ref()
 5161                            .zip(editor.project.clone())
 5162                            .map(|(tasks, project)| {
 5163                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5164                            });
 5165
 5166                    Some(cx.spawn_in(window, async move |editor, cx| {
 5167                        let task_context = match task_context {
 5168                            Some(task_context) => task_context.await,
 5169                            None => None,
 5170                        };
 5171                        let resolved_tasks =
 5172                            tasks
 5173                                .zip(task_context.clone())
 5174                                .map(|(tasks, task_context)| ResolvedTasks {
 5175                                    templates: tasks.resolve(&task_context).collect(),
 5176                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5177                                        multibuffer_point.row,
 5178                                        tasks.column,
 5179                                    )),
 5180                                });
 5181                        let spawn_straight_away = quick_launch
 5182                            && resolved_tasks
 5183                                .as_ref()
 5184                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5185                            && code_actions
 5186                                .as_ref()
 5187                                .map_or(true, |actions| actions.is_empty());
 5188                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5189                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5190                                maybe!({
 5191                                    let project = editor.project.as_ref()?;
 5192                                    let dap_store = project.read(cx).dap_store();
 5193                                    let mut scenarios = vec![];
 5194                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5195                                    let debug_adapter: SharedString = buffer
 5196                                        .read(cx)
 5197                                        .language()?
 5198                                        .context_provider()?
 5199                                        .debug_adapter()?
 5200                                        .into();
 5201                                    dap_store.update(cx, |this, cx| {
 5202                                        for (_, task) in &resolved_tasks.templates {
 5203                                            if let Some(scenario) = this
 5204                                                .debug_scenario_for_build_task(
 5205                                                    task.resolved.clone(),
 5206                                                    SharedString::from(
 5207                                                        task.original_task().label.clone(),
 5208                                                    ),
 5209                                                    debug_adapter.clone(),
 5210                                                    cx,
 5211                                                )
 5212                                            {
 5213                                                scenarios.push(scenario);
 5214                                            }
 5215                                        }
 5216                                    });
 5217                                    Some(scenarios)
 5218                                })
 5219                                .unwrap_or_default()
 5220                            } else {
 5221                                vec![]
 5222                            }
 5223                        })?;
 5224                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5225                            *editor.context_menu.borrow_mut() =
 5226                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5227                                    buffer,
 5228                                    actions: CodeActionContents::new(
 5229                                        resolved_tasks,
 5230                                        code_actions,
 5231                                        debug_scenarios,
 5232                                        task_context.unwrap_or_default(),
 5233                                    ),
 5234                                    selected_item: Default::default(),
 5235                                    scroll_handle: UniformListScrollHandle::default(),
 5236                                    deployed_from_indicator,
 5237                                }));
 5238                            if spawn_straight_away {
 5239                                if let Some(task) = editor.confirm_code_action(
 5240                                    &ConfirmCodeAction { item_ix: Some(0) },
 5241                                    window,
 5242                                    cx,
 5243                                ) {
 5244                                    cx.notify();
 5245                                    return task;
 5246                                }
 5247                            }
 5248                            cx.notify();
 5249                            Task::ready(Ok(()))
 5250                        }) {
 5251                            task.await
 5252                        } else {
 5253                            Ok(())
 5254                        }
 5255                    }))
 5256                } else {
 5257                    Some(Task::ready(Ok(())))
 5258                }
 5259            })?;
 5260            if let Some(task) = spawned_test_task {
 5261                task.await?;
 5262            }
 5263
 5264            Ok::<_, anyhow::Error>(())
 5265        })
 5266        .detach_and_log_err(cx);
 5267    }
 5268
 5269    pub fn confirm_code_action(
 5270        &mut self,
 5271        action: &ConfirmCodeAction,
 5272        window: &mut Window,
 5273        cx: &mut Context<Self>,
 5274    ) -> Option<Task<Result<()>>> {
 5275        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5276
 5277        let actions_menu =
 5278            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5279                menu
 5280            } else {
 5281                return None;
 5282            };
 5283
 5284        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5285        let action = actions_menu.actions.get(action_ix)?;
 5286        let title = action.label();
 5287        let buffer = actions_menu.buffer;
 5288        let workspace = self.workspace()?;
 5289
 5290        match action {
 5291            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5292                workspace.update(cx, |workspace, cx| {
 5293                    workspace.schedule_resolved_task(
 5294                        task_source_kind,
 5295                        resolved_task,
 5296                        false,
 5297                        window,
 5298                        cx,
 5299                    );
 5300
 5301                    Some(Task::ready(Ok(())))
 5302                })
 5303            }
 5304            CodeActionsItem::CodeAction {
 5305                excerpt_id,
 5306                action,
 5307                provider,
 5308            } => {
 5309                let apply_code_action =
 5310                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5311                let workspace = workspace.downgrade();
 5312                Some(cx.spawn_in(window, async move |editor, cx| {
 5313                    let project_transaction = apply_code_action.await?;
 5314                    Self::open_project_transaction(
 5315                        &editor,
 5316                        workspace,
 5317                        project_transaction,
 5318                        title,
 5319                        cx,
 5320                    )
 5321                    .await
 5322                }))
 5323            }
 5324            CodeActionsItem::DebugScenario(scenario) => {
 5325                let context = actions_menu.actions.context.clone();
 5326
 5327                workspace.update(cx, |workspace, cx| {
 5328                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5329                });
 5330                Some(Task::ready(Ok(())))
 5331            }
 5332        }
 5333    }
 5334
 5335    pub async fn open_project_transaction(
 5336        this: &WeakEntity<Editor>,
 5337        workspace: WeakEntity<Workspace>,
 5338        transaction: ProjectTransaction,
 5339        title: String,
 5340        cx: &mut AsyncWindowContext,
 5341    ) -> Result<()> {
 5342        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5343        cx.update(|_, cx| {
 5344            entries.sort_unstable_by_key(|(buffer, _)| {
 5345                buffer.read(cx).file().map(|f| f.path().clone())
 5346            });
 5347        })?;
 5348
 5349        // If the project transaction's edits are all contained within this editor, then
 5350        // avoid opening a new editor to display them.
 5351
 5352        if let Some((buffer, transaction)) = entries.first() {
 5353            if entries.len() == 1 {
 5354                let excerpt = this.update(cx, |editor, cx| {
 5355                    editor
 5356                        .buffer()
 5357                        .read(cx)
 5358                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5359                })?;
 5360                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5361                    if excerpted_buffer == *buffer {
 5362                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5363                            let excerpt_range = excerpt_range.to_offset(buffer);
 5364                            buffer
 5365                                .edited_ranges_for_transaction::<usize>(transaction)
 5366                                .all(|range| {
 5367                                    excerpt_range.start <= range.start
 5368                                        && excerpt_range.end >= range.end
 5369                                })
 5370                        })?;
 5371
 5372                        if all_edits_within_excerpt {
 5373                            return Ok(());
 5374                        }
 5375                    }
 5376                }
 5377            }
 5378        } else {
 5379            return Ok(());
 5380        }
 5381
 5382        let mut ranges_to_highlight = Vec::new();
 5383        let excerpt_buffer = cx.new(|cx| {
 5384            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5385            for (buffer_handle, transaction) in &entries {
 5386                let edited_ranges = buffer_handle
 5387                    .read(cx)
 5388                    .edited_ranges_for_transaction::<Point>(transaction)
 5389                    .collect::<Vec<_>>();
 5390                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5391                    PathKey::for_buffer(buffer_handle, cx),
 5392                    buffer_handle.clone(),
 5393                    edited_ranges,
 5394                    DEFAULT_MULTIBUFFER_CONTEXT,
 5395                    cx,
 5396                );
 5397
 5398                ranges_to_highlight.extend(ranges);
 5399            }
 5400            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5401            multibuffer
 5402        })?;
 5403
 5404        workspace.update_in(cx, |workspace, window, cx| {
 5405            let project = workspace.project().clone();
 5406            let editor =
 5407                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5408            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5409            editor.update(cx, |editor, cx| {
 5410                editor.highlight_background::<Self>(
 5411                    &ranges_to_highlight,
 5412                    |theme| theme.editor_highlighted_line_background,
 5413                    cx,
 5414                );
 5415            });
 5416        })?;
 5417
 5418        Ok(())
 5419    }
 5420
 5421    pub fn clear_code_action_providers(&mut self) {
 5422        self.code_action_providers.clear();
 5423        self.available_code_actions.take();
 5424    }
 5425
 5426    pub fn add_code_action_provider(
 5427        &mut self,
 5428        provider: Rc<dyn CodeActionProvider>,
 5429        window: &mut Window,
 5430        cx: &mut Context<Self>,
 5431    ) {
 5432        if self
 5433            .code_action_providers
 5434            .iter()
 5435            .any(|existing_provider| existing_provider.id() == provider.id())
 5436        {
 5437            return;
 5438        }
 5439
 5440        self.code_action_providers.push(provider);
 5441        self.refresh_code_actions(window, cx);
 5442    }
 5443
 5444    pub fn remove_code_action_provider(
 5445        &mut self,
 5446        id: Arc<str>,
 5447        window: &mut Window,
 5448        cx: &mut Context<Self>,
 5449    ) {
 5450        self.code_action_providers
 5451            .retain(|provider| provider.id() != id);
 5452        self.refresh_code_actions(window, cx);
 5453    }
 5454
 5455    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5456        let newest_selection = self.selections.newest_anchor().clone();
 5457        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5458        let buffer = self.buffer.read(cx);
 5459        if newest_selection.head().diff_base_anchor.is_some() {
 5460            return None;
 5461        }
 5462        let (start_buffer, start) =
 5463            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5464        let (end_buffer, end) =
 5465            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5466        if start_buffer != end_buffer {
 5467            return None;
 5468        }
 5469
 5470        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5471            cx.background_executor()
 5472                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5473                .await;
 5474
 5475            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5476                let providers = this.code_action_providers.clone();
 5477                let tasks = this
 5478                    .code_action_providers
 5479                    .iter()
 5480                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5481                    .collect::<Vec<_>>();
 5482                (providers, tasks)
 5483            })?;
 5484
 5485            let mut actions = Vec::new();
 5486            for (provider, provider_actions) in
 5487                providers.into_iter().zip(future::join_all(tasks).await)
 5488            {
 5489                if let Some(provider_actions) = provider_actions.log_err() {
 5490                    actions.extend(provider_actions.into_iter().map(|action| {
 5491                        AvailableCodeAction {
 5492                            excerpt_id: newest_selection.start.excerpt_id,
 5493                            action,
 5494                            provider: provider.clone(),
 5495                        }
 5496                    }));
 5497                }
 5498            }
 5499
 5500            this.update(cx, |this, cx| {
 5501                this.available_code_actions = if actions.is_empty() {
 5502                    None
 5503                } else {
 5504                    Some((
 5505                        Location {
 5506                            buffer: start_buffer,
 5507                            range: start..end,
 5508                        },
 5509                        actions.into(),
 5510                    ))
 5511                };
 5512                cx.notify();
 5513            })
 5514        }));
 5515        None
 5516    }
 5517
 5518    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5519        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5520            self.show_git_blame_inline = false;
 5521
 5522            self.show_git_blame_inline_delay_task =
 5523                Some(cx.spawn_in(window, async move |this, cx| {
 5524                    cx.background_executor().timer(delay).await;
 5525
 5526                    this.update(cx, |this, cx| {
 5527                        this.show_git_blame_inline = true;
 5528                        cx.notify();
 5529                    })
 5530                    .log_err();
 5531                }));
 5532        }
 5533    }
 5534
 5535    fn show_blame_popover(
 5536        &mut self,
 5537        blame_entry: &BlameEntry,
 5538        position: gpui::Point<Pixels>,
 5539        cx: &mut Context<Self>,
 5540    ) {
 5541        if let Some(state) = &mut self.inline_blame_popover {
 5542            state.hide_task.take();
 5543            cx.notify();
 5544        } else {
 5545            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5546            let show_task = cx.spawn(async move |editor, cx| {
 5547                cx.background_executor()
 5548                    .timer(std::time::Duration::from_millis(delay))
 5549                    .await;
 5550                editor
 5551                    .update(cx, |editor, cx| {
 5552                        if let Some(state) = &mut editor.inline_blame_popover {
 5553                            state.show_task = None;
 5554                            cx.notify();
 5555                        }
 5556                    })
 5557                    .ok();
 5558            });
 5559            let Some(blame) = self.blame.as_ref() else {
 5560                return;
 5561            };
 5562            let blame = blame.read(cx);
 5563            let details = blame.details_for_entry(&blame_entry);
 5564            let markdown = cx.new(|cx| {
 5565                Markdown::new(
 5566                    details
 5567                        .as_ref()
 5568                        .map(|message| message.message.clone())
 5569                        .unwrap_or_default(),
 5570                    None,
 5571                    None,
 5572                    cx,
 5573                )
 5574            });
 5575            self.inline_blame_popover = Some(InlineBlamePopover {
 5576                position,
 5577                show_task: Some(show_task),
 5578                hide_task: None,
 5579                popover_bounds: None,
 5580                popover_state: InlineBlamePopoverState {
 5581                    scroll_handle: ScrollHandle::new(),
 5582                    commit_message: details,
 5583                    markdown,
 5584                },
 5585            });
 5586        }
 5587    }
 5588
 5589    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5590        if let Some(state) = &mut self.inline_blame_popover {
 5591            if state.show_task.is_some() {
 5592                self.inline_blame_popover.take();
 5593                cx.notify();
 5594            } else {
 5595                let hide_task = cx.spawn(async move |editor, cx| {
 5596                    cx.background_executor()
 5597                        .timer(std::time::Duration::from_millis(100))
 5598                        .await;
 5599                    editor
 5600                        .update(cx, |editor, cx| {
 5601                            editor.inline_blame_popover.take();
 5602                            cx.notify();
 5603                        })
 5604                        .ok();
 5605                });
 5606                state.hide_task = Some(hide_task);
 5607            }
 5608        }
 5609    }
 5610
 5611    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5612        if self.pending_rename.is_some() {
 5613            return None;
 5614        }
 5615
 5616        let provider = self.semantics_provider.clone()?;
 5617        let buffer = self.buffer.read(cx);
 5618        let newest_selection = self.selections.newest_anchor().clone();
 5619        let cursor_position = newest_selection.head();
 5620        let (cursor_buffer, cursor_buffer_position) =
 5621            buffer.text_anchor_for_position(cursor_position, cx)?;
 5622        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5623        if cursor_buffer != tail_buffer {
 5624            return None;
 5625        }
 5626        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5627        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5628            cx.background_executor()
 5629                .timer(Duration::from_millis(debounce))
 5630                .await;
 5631
 5632            let highlights = if let Some(highlights) = cx
 5633                .update(|cx| {
 5634                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5635                })
 5636                .ok()
 5637                .flatten()
 5638            {
 5639                highlights.await.log_err()
 5640            } else {
 5641                None
 5642            };
 5643
 5644            if let Some(highlights) = highlights {
 5645                this.update(cx, |this, cx| {
 5646                    if this.pending_rename.is_some() {
 5647                        return;
 5648                    }
 5649
 5650                    let buffer_id = cursor_position.buffer_id;
 5651                    let buffer = this.buffer.read(cx);
 5652                    if !buffer
 5653                        .text_anchor_for_position(cursor_position, cx)
 5654                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5655                    {
 5656                        return;
 5657                    }
 5658
 5659                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5660                    let mut write_ranges = Vec::new();
 5661                    let mut read_ranges = Vec::new();
 5662                    for highlight in highlights {
 5663                        for (excerpt_id, excerpt_range) in
 5664                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5665                        {
 5666                            let start = highlight
 5667                                .range
 5668                                .start
 5669                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5670                            let end = highlight
 5671                                .range
 5672                                .end
 5673                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5674                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5675                                continue;
 5676                            }
 5677
 5678                            let range = Anchor {
 5679                                buffer_id,
 5680                                excerpt_id,
 5681                                text_anchor: start,
 5682                                diff_base_anchor: None,
 5683                            }..Anchor {
 5684                                buffer_id,
 5685                                excerpt_id,
 5686                                text_anchor: end,
 5687                                diff_base_anchor: None,
 5688                            };
 5689                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5690                                write_ranges.push(range);
 5691                            } else {
 5692                                read_ranges.push(range);
 5693                            }
 5694                        }
 5695                    }
 5696
 5697                    this.highlight_background::<DocumentHighlightRead>(
 5698                        &read_ranges,
 5699                        |theme| theme.editor_document_highlight_read_background,
 5700                        cx,
 5701                    );
 5702                    this.highlight_background::<DocumentHighlightWrite>(
 5703                        &write_ranges,
 5704                        |theme| theme.editor_document_highlight_write_background,
 5705                        cx,
 5706                    );
 5707                    cx.notify();
 5708                })
 5709                .log_err();
 5710            }
 5711        }));
 5712        None
 5713    }
 5714
 5715    fn prepare_highlight_query_from_selection(
 5716        &mut self,
 5717        cx: &mut Context<Editor>,
 5718    ) -> Option<(String, Range<Anchor>)> {
 5719        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 5720            return None;
 5721        }
 5722        if !EditorSettings::get_global(cx).selection_highlight {
 5723            return None;
 5724        }
 5725        if self.selections.count() != 1 || self.selections.line_mode {
 5726            return None;
 5727        }
 5728        let selection = self.selections.newest::<Point>(cx);
 5729        if selection.is_empty() || selection.start.row != selection.end.row {
 5730            return None;
 5731        }
 5732        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5733        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 5734        let query = multi_buffer_snapshot
 5735            .text_for_range(selection_anchor_range.clone())
 5736            .collect::<String>();
 5737        if query.trim().is_empty() {
 5738            return None;
 5739        }
 5740        Some((query, selection_anchor_range))
 5741    }
 5742
 5743    fn update_selection_occurrence_highlights(
 5744        &mut self,
 5745        query_text: String,
 5746        query_range: Range<Anchor>,
 5747        multi_buffer_range_to_query: Range<Point>,
 5748        use_debounce: bool,
 5749        window: &mut Window,
 5750        cx: &mut Context<Editor>,
 5751    ) -> Task<()> {
 5752        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5753        cx.spawn_in(window, async move |editor, cx| {
 5754            if use_debounce {
 5755                cx.background_executor()
 5756                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 5757                    .await;
 5758            }
 5759            let match_task = cx.background_spawn(async move {
 5760                let buffer_ranges = multi_buffer_snapshot
 5761                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 5762                    .into_iter()
 5763                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 5764                let mut match_ranges = Vec::new();
 5765                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 5766                    match_ranges.extend(
 5767                        project::search::SearchQuery::text(
 5768                            query_text.clone(),
 5769                            false,
 5770                            false,
 5771                            false,
 5772                            Default::default(),
 5773                            Default::default(),
 5774                            false,
 5775                            None,
 5776                        )
 5777                        .unwrap()
 5778                        .search(&buffer_snapshot, Some(search_range.clone()))
 5779                        .await
 5780                        .into_iter()
 5781                        .filter_map(|match_range| {
 5782                            let match_start = buffer_snapshot
 5783                                .anchor_after(search_range.start + match_range.start);
 5784                            let match_end =
 5785                                buffer_snapshot.anchor_before(search_range.start + match_range.end);
 5786                            let match_anchor_range = Anchor::range_in_buffer(
 5787                                excerpt_id,
 5788                                buffer_snapshot.remote_id(),
 5789                                match_start..match_end,
 5790                            );
 5791                            (match_anchor_range != query_range).then_some(match_anchor_range)
 5792                        }),
 5793                    );
 5794                }
 5795                match_ranges
 5796            });
 5797            let match_ranges = match_task.await;
 5798            editor
 5799                .update_in(cx, |editor, _, cx| {
 5800                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5801                    if !match_ranges.is_empty() {
 5802                        editor.highlight_background::<SelectedTextHighlight>(
 5803                            &match_ranges,
 5804                            |theme| theme.editor_document_highlight_bracket_background,
 5805                            cx,
 5806                        )
 5807                    }
 5808                })
 5809                .log_err();
 5810        })
 5811    }
 5812
 5813    fn refresh_selected_text_highlights(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 5814        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 5815        else {
 5816            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 5817            self.quick_selection_highlight_task.take();
 5818            self.debounced_selection_highlight_task.take();
 5819            return;
 5820        };
 5821        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5822        if self
 5823            .quick_selection_highlight_task
 5824            .as_ref()
 5825            .map_or(true, |(prev_anchor_range, _)| {
 5826                prev_anchor_range != &query_range
 5827            })
 5828        {
 5829            let multi_buffer_visible_start = self
 5830                .scroll_manager
 5831                .anchor()
 5832                .anchor
 5833                .to_point(&multi_buffer_snapshot);
 5834            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5835                multi_buffer_visible_start
 5836                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5837                Bias::Left,
 5838            );
 5839            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5840            self.quick_selection_highlight_task = Some((
 5841                query_range.clone(),
 5842                self.update_selection_occurrence_highlights(
 5843                    query_text.clone(),
 5844                    query_range.clone(),
 5845                    multi_buffer_visible_range,
 5846                    false,
 5847                    window,
 5848                    cx,
 5849                ),
 5850            ));
 5851        }
 5852        if self
 5853            .debounced_selection_highlight_task
 5854            .as_ref()
 5855            .map_or(true, |(prev_anchor_range, _)| {
 5856                prev_anchor_range != &query_range
 5857            })
 5858        {
 5859            let multi_buffer_start = multi_buffer_snapshot
 5860                .anchor_before(0)
 5861                .to_point(&multi_buffer_snapshot);
 5862            let multi_buffer_end = multi_buffer_snapshot
 5863                .anchor_after(multi_buffer_snapshot.len())
 5864                .to_point(&multi_buffer_snapshot);
 5865            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 5866            self.debounced_selection_highlight_task = Some((
 5867                query_range.clone(),
 5868                self.update_selection_occurrence_highlights(
 5869                    query_text,
 5870                    query_range,
 5871                    multi_buffer_full_range,
 5872                    true,
 5873                    window,
 5874                    cx,
 5875                ),
 5876            ));
 5877        }
 5878    }
 5879
 5880    pub fn refresh_inline_completion(
 5881        &mut self,
 5882        debounce: bool,
 5883        user_requested: bool,
 5884        window: &mut Window,
 5885        cx: &mut Context<Self>,
 5886    ) -> Option<()> {
 5887        let provider = self.edit_prediction_provider()?;
 5888        let cursor = self.selections.newest_anchor().head();
 5889        let (buffer, cursor_buffer_position) =
 5890            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5891
 5892        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 5893            self.discard_inline_completion(false, cx);
 5894            return None;
 5895        }
 5896
 5897        if !user_requested
 5898            && (!self.should_show_edit_predictions()
 5899                || !self.is_focused(window)
 5900                || buffer.read(cx).is_empty())
 5901        {
 5902            self.discard_inline_completion(false, cx);
 5903            return None;
 5904        }
 5905
 5906        self.update_visible_inline_completion(window, cx);
 5907        provider.refresh(
 5908            self.project.clone(),
 5909            buffer,
 5910            cursor_buffer_position,
 5911            debounce,
 5912            cx,
 5913        );
 5914        Some(())
 5915    }
 5916
 5917    fn show_edit_predictions_in_menu(&self) -> bool {
 5918        match self.edit_prediction_settings {
 5919            EditPredictionSettings::Disabled => false,
 5920            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 5921        }
 5922    }
 5923
 5924    pub fn edit_predictions_enabled(&self) -> bool {
 5925        match self.edit_prediction_settings {
 5926            EditPredictionSettings::Disabled => false,
 5927            EditPredictionSettings::Enabled { .. } => true,
 5928        }
 5929    }
 5930
 5931    fn edit_prediction_requires_modifier(&self) -> bool {
 5932        match self.edit_prediction_settings {
 5933            EditPredictionSettings::Disabled => false,
 5934            EditPredictionSettings::Enabled {
 5935                preview_requires_modifier,
 5936                ..
 5937            } => preview_requires_modifier,
 5938        }
 5939    }
 5940
 5941    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 5942        if self.edit_prediction_provider.is_none() {
 5943            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 5944        } else {
 5945            let selection = self.selections.newest_anchor();
 5946            let cursor = selection.head();
 5947
 5948            if let Some((buffer, cursor_buffer_position)) =
 5949                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5950            {
 5951                self.edit_prediction_settings =
 5952                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 5953            }
 5954        }
 5955    }
 5956
 5957    fn edit_prediction_settings_at_position(
 5958        &self,
 5959        buffer: &Entity<Buffer>,
 5960        buffer_position: language::Anchor,
 5961        cx: &App,
 5962    ) -> EditPredictionSettings {
 5963        if !self.mode.is_full()
 5964            || !self.show_inline_completions_override.unwrap_or(true)
 5965            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 5966        {
 5967            return EditPredictionSettings::Disabled;
 5968        }
 5969
 5970        let buffer = buffer.read(cx);
 5971
 5972        let file = buffer.file();
 5973
 5974        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 5975            return EditPredictionSettings::Disabled;
 5976        };
 5977
 5978        let by_provider = matches!(
 5979            self.menu_inline_completions_policy,
 5980            MenuInlineCompletionsPolicy::ByProvider
 5981        );
 5982
 5983        let show_in_menu = by_provider
 5984            && self
 5985                .edit_prediction_provider
 5986                .as_ref()
 5987                .map_or(false, |provider| {
 5988                    provider.provider.show_completions_in_menu()
 5989                });
 5990
 5991        let preview_requires_modifier =
 5992            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 5993
 5994        EditPredictionSettings::Enabled {
 5995            show_in_menu,
 5996            preview_requires_modifier,
 5997        }
 5998    }
 5999
 6000    fn should_show_edit_predictions(&self) -> bool {
 6001        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6002    }
 6003
 6004    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6005        matches!(
 6006            self.edit_prediction_preview,
 6007            EditPredictionPreview::Active { .. }
 6008        )
 6009    }
 6010
 6011    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6012        let cursor = self.selections.newest_anchor().head();
 6013        if let Some((buffer, cursor_position)) =
 6014            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6015        {
 6016            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6017        } else {
 6018            false
 6019        }
 6020    }
 6021
 6022    fn edit_predictions_enabled_in_buffer(
 6023        &self,
 6024        buffer: &Entity<Buffer>,
 6025        buffer_position: language::Anchor,
 6026        cx: &App,
 6027    ) -> bool {
 6028        maybe!({
 6029            if self.read_only(cx) {
 6030                return Some(false);
 6031            }
 6032            let provider = self.edit_prediction_provider()?;
 6033            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6034                return Some(false);
 6035            }
 6036            let buffer = buffer.read(cx);
 6037            let Some(file) = buffer.file() else {
 6038                return Some(true);
 6039            };
 6040            let settings = all_language_settings(Some(file), cx);
 6041            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6042        })
 6043        .unwrap_or(false)
 6044    }
 6045
 6046    fn cycle_inline_completion(
 6047        &mut self,
 6048        direction: Direction,
 6049        window: &mut Window,
 6050        cx: &mut Context<Self>,
 6051    ) -> Option<()> {
 6052        let provider = self.edit_prediction_provider()?;
 6053        let cursor = self.selections.newest_anchor().head();
 6054        let (buffer, cursor_buffer_position) =
 6055            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6056        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6057            return None;
 6058        }
 6059
 6060        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6061        self.update_visible_inline_completion(window, cx);
 6062
 6063        Some(())
 6064    }
 6065
 6066    pub fn show_inline_completion(
 6067        &mut self,
 6068        _: &ShowEditPrediction,
 6069        window: &mut Window,
 6070        cx: &mut Context<Self>,
 6071    ) {
 6072        if !self.has_active_inline_completion() {
 6073            self.refresh_inline_completion(false, true, window, cx);
 6074            return;
 6075        }
 6076
 6077        self.update_visible_inline_completion(window, cx);
 6078    }
 6079
 6080    pub fn display_cursor_names(
 6081        &mut self,
 6082        _: &DisplayCursorNames,
 6083        window: &mut Window,
 6084        cx: &mut Context<Self>,
 6085    ) {
 6086        self.show_cursor_names(window, cx);
 6087    }
 6088
 6089    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6090        self.show_cursor_names = true;
 6091        cx.notify();
 6092        cx.spawn_in(window, async move |this, cx| {
 6093            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6094            this.update(cx, |this, cx| {
 6095                this.show_cursor_names = false;
 6096                cx.notify()
 6097            })
 6098            .ok()
 6099        })
 6100        .detach();
 6101    }
 6102
 6103    pub fn next_edit_prediction(
 6104        &mut self,
 6105        _: &NextEditPrediction,
 6106        window: &mut Window,
 6107        cx: &mut Context<Self>,
 6108    ) {
 6109        if self.has_active_inline_completion() {
 6110            self.cycle_inline_completion(Direction::Next, window, cx);
 6111        } else {
 6112            let is_copilot_disabled = self
 6113                .refresh_inline_completion(false, true, window, cx)
 6114                .is_none();
 6115            if is_copilot_disabled {
 6116                cx.propagate();
 6117            }
 6118        }
 6119    }
 6120
 6121    pub fn previous_edit_prediction(
 6122        &mut self,
 6123        _: &PreviousEditPrediction,
 6124        window: &mut Window,
 6125        cx: &mut Context<Self>,
 6126    ) {
 6127        if self.has_active_inline_completion() {
 6128            self.cycle_inline_completion(Direction::Prev, window, cx);
 6129        } else {
 6130            let is_copilot_disabled = self
 6131                .refresh_inline_completion(false, true, window, cx)
 6132                .is_none();
 6133            if is_copilot_disabled {
 6134                cx.propagate();
 6135            }
 6136        }
 6137    }
 6138
 6139    pub fn accept_edit_prediction(
 6140        &mut self,
 6141        _: &AcceptEditPrediction,
 6142        window: &mut Window,
 6143        cx: &mut Context<Self>,
 6144    ) {
 6145        if self.show_edit_predictions_in_menu() {
 6146            self.hide_context_menu(window, cx);
 6147        }
 6148
 6149        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6150            return;
 6151        };
 6152
 6153        self.report_inline_completion_event(
 6154            active_inline_completion.completion_id.clone(),
 6155            true,
 6156            cx,
 6157        );
 6158
 6159        match &active_inline_completion.completion {
 6160            InlineCompletion::Move { target, .. } => {
 6161                let target = *target;
 6162
 6163                if let Some(position_map) = &self.last_position_map {
 6164                    if position_map
 6165                        .visible_row_range
 6166                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6167                        || !self.edit_prediction_requires_modifier()
 6168                    {
 6169                        self.unfold_ranges(&[target..target], true, false, cx);
 6170                        // Note that this is also done in vim's handler of the Tab action.
 6171                        self.change_selections(
 6172                            Some(Autoscroll::newest()),
 6173                            window,
 6174                            cx,
 6175                            |selections| {
 6176                                selections.select_anchor_ranges([target..target]);
 6177                            },
 6178                        );
 6179                        self.clear_row_highlights::<EditPredictionPreview>();
 6180
 6181                        self.edit_prediction_preview
 6182                            .set_previous_scroll_position(None);
 6183                    } else {
 6184                        self.edit_prediction_preview
 6185                            .set_previous_scroll_position(Some(
 6186                                position_map.snapshot.scroll_anchor,
 6187                            ));
 6188
 6189                        self.highlight_rows::<EditPredictionPreview>(
 6190                            target..target,
 6191                            cx.theme().colors().editor_highlighted_line_background,
 6192                            RowHighlightOptions {
 6193                                autoscroll: true,
 6194                                ..Default::default()
 6195                            },
 6196                            cx,
 6197                        );
 6198                        self.request_autoscroll(Autoscroll::fit(), cx);
 6199                    }
 6200                }
 6201            }
 6202            InlineCompletion::Edit { edits, .. } => {
 6203                if let Some(provider) = self.edit_prediction_provider() {
 6204                    provider.accept(cx);
 6205                }
 6206
 6207                let snapshot = self.buffer.read(cx).snapshot(cx);
 6208                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6209
 6210                self.buffer.update(cx, |buffer, cx| {
 6211                    buffer.edit(edits.iter().cloned(), None, cx)
 6212                });
 6213
 6214                self.change_selections(None, window, cx, |s| {
 6215                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6216                });
 6217
 6218                self.update_visible_inline_completion(window, cx);
 6219                if self.active_inline_completion.is_none() {
 6220                    self.refresh_inline_completion(true, true, window, cx);
 6221                }
 6222
 6223                cx.notify();
 6224            }
 6225        }
 6226
 6227        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6228    }
 6229
 6230    pub fn accept_partial_inline_completion(
 6231        &mut self,
 6232        _: &AcceptPartialEditPrediction,
 6233        window: &mut Window,
 6234        cx: &mut Context<Self>,
 6235    ) {
 6236        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6237            return;
 6238        };
 6239        if self.selections.count() != 1 {
 6240            return;
 6241        }
 6242
 6243        self.report_inline_completion_event(
 6244            active_inline_completion.completion_id.clone(),
 6245            true,
 6246            cx,
 6247        );
 6248
 6249        match &active_inline_completion.completion {
 6250            InlineCompletion::Move { target, .. } => {
 6251                let target = *target;
 6252                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6253                    selections.select_anchor_ranges([target..target]);
 6254                });
 6255            }
 6256            InlineCompletion::Edit { edits, .. } => {
 6257                // Find an insertion that starts at the cursor position.
 6258                let snapshot = self.buffer.read(cx).snapshot(cx);
 6259                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6260                let insertion = edits.iter().find_map(|(range, text)| {
 6261                    let range = range.to_offset(&snapshot);
 6262                    if range.is_empty() && range.start == cursor_offset {
 6263                        Some(text)
 6264                    } else {
 6265                        None
 6266                    }
 6267                });
 6268
 6269                if let Some(text) = insertion {
 6270                    let mut partial_completion = text
 6271                        .chars()
 6272                        .by_ref()
 6273                        .take_while(|c| c.is_alphabetic())
 6274                        .collect::<String>();
 6275                    if partial_completion.is_empty() {
 6276                        partial_completion = text
 6277                            .chars()
 6278                            .by_ref()
 6279                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6280                            .collect::<String>();
 6281                    }
 6282
 6283                    cx.emit(EditorEvent::InputHandled {
 6284                        utf16_range_to_replace: None,
 6285                        text: partial_completion.clone().into(),
 6286                    });
 6287
 6288                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6289
 6290                    self.refresh_inline_completion(true, true, window, cx);
 6291                    cx.notify();
 6292                } else {
 6293                    self.accept_edit_prediction(&Default::default(), window, cx);
 6294                }
 6295            }
 6296        }
 6297    }
 6298
 6299    fn discard_inline_completion(
 6300        &mut self,
 6301        should_report_inline_completion_event: bool,
 6302        cx: &mut Context<Self>,
 6303    ) -> bool {
 6304        if should_report_inline_completion_event {
 6305            let completion_id = self
 6306                .active_inline_completion
 6307                .as_ref()
 6308                .and_then(|active_completion| active_completion.completion_id.clone());
 6309
 6310            self.report_inline_completion_event(completion_id, false, cx);
 6311        }
 6312
 6313        if let Some(provider) = self.edit_prediction_provider() {
 6314            provider.discard(cx);
 6315        }
 6316
 6317        self.take_active_inline_completion(cx)
 6318    }
 6319
 6320    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6321        let Some(provider) = self.edit_prediction_provider() else {
 6322            return;
 6323        };
 6324
 6325        let Some((_, buffer, _)) = self
 6326            .buffer
 6327            .read(cx)
 6328            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6329        else {
 6330            return;
 6331        };
 6332
 6333        let extension = buffer
 6334            .read(cx)
 6335            .file()
 6336            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6337
 6338        let event_type = match accepted {
 6339            true => "Edit Prediction Accepted",
 6340            false => "Edit Prediction Discarded",
 6341        };
 6342        telemetry::event!(
 6343            event_type,
 6344            provider = provider.name(),
 6345            prediction_id = id,
 6346            suggestion_accepted = accepted,
 6347            file_extension = extension,
 6348        );
 6349    }
 6350
 6351    pub fn has_active_inline_completion(&self) -> bool {
 6352        self.active_inline_completion.is_some()
 6353    }
 6354
 6355    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6356        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6357            return false;
 6358        };
 6359
 6360        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6361        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6362        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6363        true
 6364    }
 6365
 6366    /// Returns true when we're displaying the edit prediction popover below the cursor
 6367    /// like we are not previewing and the LSP autocomplete menu is visible
 6368    /// or we are in `when_holding_modifier` mode.
 6369    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6370        if self.edit_prediction_preview_is_active()
 6371            || !self.show_edit_predictions_in_menu()
 6372            || !self.edit_predictions_enabled()
 6373        {
 6374            return false;
 6375        }
 6376
 6377        if self.has_visible_completions_menu() {
 6378            return true;
 6379        }
 6380
 6381        has_completion && self.edit_prediction_requires_modifier()
 6382    }
 6383
 6384    fn handle_modifiers_changed(
 6385        &mut self,
 6386        modifiers: Modifiers,
 6387        position_map: &PositionMap,
 6388        window: &mut Window,
 6389        cx: &mut Context<Self>,
 6390    ) {
 6391        if self.show_edit_predictions_in_menu() {
 6392            self.update_edit_prediction_preview(&modifiers, window, cx);
 6393        }
 6394
 6395        self.update_selection_mode(&modifiers, position_map, window, cx);
 6396
 6397        let mouse_position = window.mouse_position();
 6398        if !position_map.text_hitbox.is_hovered(window) {
 6399            return;
 6400        }
 6401
 6402        self.update_hovered_link(
 6403            position_map.point_for_position(mouse_position),
 6404            &position_map.snapshot,
 6405            modifiers,
 6406            window,
 6407            cx,
 6408        )
 6409    }
 6410
 6411    fn update_selection_mode(
 6412        &mut self,
 6413        modifiers: &Modifiers,
 6414        position_map: &PositionMap,
 6415        window: &mut Window,
 6416        cx: &mut Context<Self>,
 6417    ) {
 6418        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6419            return;
 6420        }
 6421
 6422        let mouse_position = window.mouse_position();
 6423        let point_for_position = position_map.point_for_position(mouse_position);
 6424        let position = point_for_position.previous_valid;
 6425
 6426        self.select(
 6427            SelectPhase::BeginColumnar {
 6428                position,
 6429                reset: false,
 6430                goal_column: point_for_position.exact_unclipped.column(),
 6431            },
 6432            window,
 6433            cx,
 6434        );
 6435    }
 6436
 6437    fn update_edit_prediction_preview(
 6438        &mut self,
 6439        modifiers: &Modifiers,
 6440        window: &mut Window,
 6441        cx: &mut Context<Self>,
 6442    ) {
 6443        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6444        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6445            return;
 6446        };
 6447
 6448        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6449            if matches!(
 6450                self.edit_prediction_preview,
 6451                EditPredictionPreview::Inactive { .. }
 6452            ) {
 6453                self.edit_prediction_preview = EditPredictionPreview::Active {
 6454                    previous_scroll_position: None,
 6455                    since: Instant::now(),
 6456                };
 6457
 6458                self.update_visible_inline_completion(window, cx);
 6459                cx.notify();
 6460            }
 6461        } else if let EditPredictionPreview::Active {
 6462            previous_scroll_position,
 6463            since,
 6464        } = self.edit_prediction_preview
 6465        {
 6466            if let (Some(previous_scroll_position), Some(position_map)) =
 6467                (previous_scroll_position, self.last_position_map.as_ref())
 6468            {
 6469                self.set_scroll_position(
 6470                    previous_scroll_position
 6471                        .scroll_position(&position_map.snapshot.display_snapshot),
 6472                    window,
 6473                    cx,
 6474                );
 6475            }
 6476
 6477            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6478                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6479            };
 6480            self.clear_row_highlights::<EditPredictionPreview>();
 6481            self.update_visible_inline_completion(window, cx);
 6482            cx.notify();
 6483        }
 6484    }
 6485
 6486    fn update_visible_inline_completion(
 6487        &mut self,
 6488        _window: &mut Window,
 6489        cx: &mut Context<Self>,
 6490    ) -> Option<()> {
 6491        let selection = self.selections.newest_anchor();
 6492        let cursor = selection.head();
 6493        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6494        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6495        let excerpt_id = cursor.excerpt_id;
 6496
 6497        let show_in_menu = self.show_edit_predictions_in_menu();
 6498        let completions_menu_has_precedence = !show_in_menu
 6499            && (self.context_menu.borrow().is_some()
 6500                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6501
 6502        if completions_menu_has_precedence
 6503            || !offset_selection.is_empty()
 6504            || self
 6505                .active_inline_completion
 6506                .as_ref()
 6507                .map_or(false, |completion| {
 6508                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6509                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6510                    !invalidation_range.contains(&offset_selection.head())
 6511                })
 6512        {
 6513            self.discard_inline_completion(false, cx);
 6514            return None;
 6515        }
 6516
 6517        self.take_active_inline_completion(cx);
 6518        let Some(provider) = self.edit_prediction_provider() else {
 6519            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6520            return None;
 6521        };
 6522
 6523        let (buffer, cursor_buffer_position) =
 6524            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6525
 6526        self.edit_prediction_settings =
 6527            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6528
 6529        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6530
 6531        if self.edit_prediction_indent_conflict {
 6532            let cursor_point = cursor.to_point(&multibuffer);
 6533
 6534            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6535
 6536            if let Some((_, indent)) = indents.iter().next() {
 6537                if indent.len == cursor_point.column {
 6538                    self.edit_prediction_indent_conflict = false;
 6539                }
 6540            }
 6541        }
 6542
 6543        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6544        let edits = inline_completion
 6545            .edits
 6546            .into_iter()
 6547            .flat_map(|(range, new_text)| {
 6548                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6549                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6550                Some((start..end, new_text))
 6551            })
 6552            .collect::<Vec<_>>();
 6553        if edits.is_empty() {
 6554            return None;
 6555        }
 6556
 6557        let first_edit_start = edits.first().unwrap().0.start;
 6558        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6559        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6560
 6561        let last_edit_end = edits.last().unwrap().0.end;
 6562        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6563        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6564
 6565        let cursor_row = cursor.to_point(&multibuffer).row;
 6566
 6567        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6568
 6569        let mut inlay_ids = Vec::new();
 6570        let invalidation_row_range;
 6571        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6572            Some(cursor_row..edit_end_row)
 6573        } else if cursor_row > edit_end_row {
 6574            Some(edit_start_row..cursor_row)
 6575        } else {
 6576            None
 6577        };
 6578        let is_move =
 6579            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6580        let completion = if is_move {
 6581            invalidation_row_range =
 6582                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6583            let target = first_edit_start;
 6584            InlineCompletion::Move { target, snapshot }
 6585        } else {
 6586            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6587                && !self.inline_completions_hidden_for_vim_mode;
 6588
 6589            if show_completions_in_buffer {
 6590                if edits
 6591                    .iter()
 6592                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6593                {
 6594                    let mut inlays = Vec::new();
 6595                    for (range, new_text) in &edits {
 6596                        let inlay = Inlay::inline_completion(
 6597                            post_inc(&mut self.next_inlay_id),
 6598                            range.start,
 6599                            new_text.as_str(),
 6600                        );
 6601                        inlay_ids.push(inlay.id);
 6602                        inlays.push(inlay);
 6603                    }
 6604
 6605                    self.splice_inlays(&[], inlays, cx);
 6606                } else {
 6607                    let background_color = cx.theme().status().deleted_background;
 6608                    self.highlight_text::<InlineCompletionHighlight>(
 6609                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6610                        HighlightStyle {
 6611                            background_color: Some(background_color),
 6612                            ..Default::default()
 6613                        },
 6614                        cx,
 6615                    );
 6616                }
 6617            }
 6618
 6619            invalidation_row_range = edit_start_row..edit_end_row;
 6620
 6621            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6622                if provider.show_tab_accept_marker() {
 6623                    EditDisplayMode::TabAccept
 6624                } else {
 6625                    EditDisplayMode::Inline
 6626                }
 6627            } else {
 6628                EditDisplayMode::DiffPopover
 6629            };
 6630
 6631            InlineCompletion::Edit {
 6632                edits,
 6633                edit_preview: inline_completion.edit_preview,
 6634                display_mode,
 6635                snapshot,
 6636            }
 6637        };
 6638
 6639        let invalidation_range = multibuffer
 6640            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6641            ..multibuffer.anchor_after(Point::new(
 6642                invalidation_row_range.end,
 6643                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6644            ));
 6645
 6646        self.stale_inline_completion_in_menu = None;
 6647        self.active_inline_completion = Some(InlineCompletionState {
 6648            inlay_ids,
 6649            completion,
 6650            completion_id: inline_completion.id,
 6651            invalidation_range,
 6652        });
 6653
 6654        cx.notify();
 6655
 6656        Some(())
 6657    }
 6658
 6659    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6660        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6661    }
 6662
 6663    fn render_code_actions_indicator(
 6664        &self,
 6665        _style: &EditorStyle,
 6666        row: DisplayRow,
 6667        is_active: bool,
 6668        breakpoint: Option<&(Anchor, Breakpoint)>,
 6669        cx: &mut Context<Self>,
 6670    ) -> Option<IconButton> {
 6671        let color = Color::Muted;
 6672        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 6673        let show_tooltip = !self.context_menu_visible();
 6674
 6675        if self.available_code_actions.is_some() {
 6676            Some(
 6677                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 6678                    .shape(ui::IconButtonShape::Square)
 6679                    .icon_size(IconSize::XSmall)
 6680                    .icon_color(color)
 6681                    .toggle_state(is_active)
 6682                    .when(show_tooltip, |this| {
 6683                        this.tooltip({
 6684                            let focus_handle = self.focus_handle.clone();
 6685                            move |window, cx| {
 6686                                Tooltip::for_action_in(
 6687                                    "Toggle Code Actions",
 6688                                    &ToggleCodeActions {
 6689                                        deployed_from_indicator: None,
 6690                                        quick_launch: false,
 6691                                    },
 6692                                    &focus_handle,
 6693                                    window,
 6694                                    cx,
 6695                                )
 6696                            }
 6697                        })
 6698                    })
 6699                    .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 6700                        let quick_launch = e.down.button == MouseButton::Left;
 6701                        window.focus(&editor.focus_handle(cx));
 6702                        editor.toggle_code_actions(
 6703                            &ToggleCodeActions {
 6704                                deployed_from_indicator: Some(row),
 6705                                quick_launch,
 6706                            },
 6707                            window,
 6708                            cx,
 6709                        );
 6710                    }))
 6711                    .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6712                        editor.set_breakpoint_context_menu(
 6713                            row,
 6714                            position,
 6715                            event.down.position,
 6716                            window,
 6717                            cx,
 6718                        );
 6719                    })),
 6720            )
 6721        } else {
 6722            None
 6723        }
 6724    }
 6725
 6726    fn clear_tasks(&mut self) {
 6727        self.tasks.clear()
 6728    }
 6729
 6730    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6731        if self.tasks.insert(key, value).is_some() {
 6732            // This case should hopefully be rare, but just in case...
 6733            log::error!(
 6734                "multiple different run targets found on a single line, only the last target will be rendered"
 6735            )
 6736        }
 6737    }
 6738
 6739    /// Get all display points of breakpoints that will be rendered within editor
 6740    ///
 6741    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6742    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6743    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6744    fn active_breakpoints(
 6745        &self,
 6746        range: Range<DisplayRow>,
 6747        window: &mut Window,
 6748        cx: &mut Context<Self>,
 6749    ) -> HashMap<DisplayRow, (Anchor, Breakpoint)> {
 6750        let mut breakpoint_display_points = HashMap::default();
 6751
 6752        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 6753            return breakpoint_display_points;
 6754        };
 6755
 6756        let snapshot = self.snapshot(window, cx);
 6757
 6758        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 6759        let Some(project) = self.project.as_ref() else {
 6760            return breakpoint_display_points;
 6761        };
 6762
 6763        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 6764            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 6765
 6766        for (buffer_snapshot, range, excerpt_id) in
 6767            multi_buffer_snapshot.range_to_buffer_ranges(range)
 6768        {
 6769            let Some(buffer) = project.read_with(cx, |this, cx| {
 6770                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 6771            }) else {
 6772                continue;
 6773            };
 6774            let breakpoints = breakpoint_store.read(cx).breakpoints(
 6775                &buffer,
 6776                Some(
 6777                    buffer_snapshot.anchor_before(range.start)
 6778                        ..buffer_snapshot.anchor_after(range.end),
 6779                ),
 6780                buffer_snapshot,
 6781                cx,
 6782            );
 6783            for (anchor, breakpoint) in breakpoints {
 6784                let multi_buffer_anchor =
 6785                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), *anchor);
 6786                let position = multi_buffer_anchor
 6787                    .to_point(&multi_buffer_snapshot)
 6788                    .to_display_point(&snapshot);
 6789
 6790                breakpoint_display_points
 6791                    .insert(position.row(), (multi_buffer_anchor, breakpoint.clone()));
 6792            }
 6793        }
 6794
 6795        breakpoint_display_points
 6796    }
 6797
 6798    fn breakpoint_context_menu(
 6799        &self,
 6800        anchor: Anchor,
 6801        window: &mut Window,
 6802        cx: &mut Context<Self>,
 6803    ) -> Entity<ui::ContextMenu> {
 6804        let weak_editor = cx.weak_entity();
 6805        let focus_handle = self.focus_handle(cx);
 6806
 6807        let row = self
 6808            .buffer
 6809            .read(cx)
 6810            .snapshot(cx)
 6811            .summary_for_anchor::<Point>(&anchor)
 6812            .row;
 6813
 6814        let breakpoint = self
 6815            .breakpoint_at_row(row, window, cx)
 6816            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 6817
 6818        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 6819            "Edit Log Breakpoint"
 6820        } else {
 6821            "Set Log Breakpoint"
 6822        };
 6823
 6824        let condition_breakpoint_msg = if breakpoint
 6825            .as_ref()
 6826            .is_some_and(|bp| bp.1.condition.is_some())
 6827        {
 6828            "Edit Condition Breakpoint"
 6829        } else {
 6830            "Set Condition Breakpoint"
 6831        };
 6832
 6833        let hit_condition_breakpoint_msg = if breakpoint
 6834            .as_ref()
 6835            .is_some_and(|bp| bp.1.hit_condition.is_some())
 6836        {
 6837            "Edit Hit Condition Breakpoint"
 6838        } else {
 6839            "Set Hit Condition Breakpoint"
 6840        };
 6841
 6842        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 6843            "Unset Breakpoint"
 6844        } else {
 6845            "Set Breakpoint"
 6846        };
 6847
 6848        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 6849            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 6850
 6851        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 6852            BreakpointState::Enabled => Some("Disable"),
 6853            BreakpointState::Disabled => Some("Enable"),
 6854        });
 6855
 6856        let (anchor, breakpoint) =
 6857            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 6858
 6859        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 6860            menu.on_blur_subscription(Subscription::new(|| {}))
 6861                .context(focus_handle)
 6862                .when(run_to_cursor, |this| {
 6863                    let weak_editor = weak_editor.clone();
 6864                    this.entry("Run to cursor", None, move |window, cx| {
 6865                        weak_editor
 6866                            .update(cx, |editor, cx| {
 6867                                editor.change_selections(None, window, cx, |s| {
 6868                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 6869                                });
 6870                            })
 6871                            .ok();
 6872
 6873                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 6874                    })
 6875                    .separator()
 6876                })
 6877                .when_some(toggle_state_msg, |this, msg| {
 6878                    this.entry(msg, None, {
 6879                        let weak_editor = weak_editor.clone();
 6880                        let breakpoint = breakpoint.clone();
 6881                        move |_window, cx| {
 6882                            weak_editor
 6883                                .update(cx, |this, cx| {
 6884                                    this.edit_breakpoint_at_anchor(
 6885                                        anchor,
 6886                                        breakpoint.as_ref().clone(),
 6887                                        BreakpointEditAction::InvertState,
 6888                                        cx,
 6889                                    );
 6890                                })
 6891                                .log_err();
 6892                        }
 6893                    })
 6894                })
 6895                .entry(set_breakpoint_msg, None, {
 6896                    let weak_editor = weak_editor.clone();
 6897                    let breakpoint = breakpoint.clone();
 6898                    move |_window, cx| {
 6899                        weak_editor
 6900                            .update(cx, |this, cx| {
 6901                                this.edit_breakpoint_at_anchor(
 6902                                    anchor,
 6903                                    breakpoint.as_ref().clone(),
 6904                                    BreakpointEditAction::Toggle,
 6905                                    cx,
 6906                                );
 6907                            })
 6908                            .log_err();
 6909                    }
 6910                })
 6911                .entry(log_breakpoint_msg, None, {
 6912                    let breakpoint = breakpoint.clone();
 6913                    let weak_editor = weak_editor.clone();
 6914                    move |window, cx| {
 6915                        weak_editor
 6916                            .update(cx, |this, cx| {
 6917                                this.add_edit_breakpoint_block(
 6918                                    anchor,
 6919                                    breakpoint.as_ref(),
 6920                                    BreakpointPromptEditAction::Log,
 6921                                    window,
 6922                                    cx,
 6923                                );
 6924                            })
 6925                            .log_err();
 6926                    }
 6927                })
 6928                .entry(condition_breakpoint_msg, None, {
 6929                    let breakpoint = breakpoint.clone();
 6930                    let weak_editor = weak_editor.clone();
 6931                    move |window, cx| {
 6932                        weak_editor
 6933                            .update(cx, |this, cx| {
 6934                                this.add_edit_breakpoint_block(
 6935                                    anchor,
 6936                                    breakpoint.as_ref(),
 6937                                    BreakpointPromptEditAction::Condition,
 6938                                    window,
 6939                                    cx,
 6940                                );
 6941                            })
 6942                            .log_err();
 6943                    }
 6944                })
 6945                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 6946                    weak_editor
 6947                        .update(cx, |this, cx| {
 6948                            this.add_edit_breakpoint_block(
 6949                                anchor,
 6950                                breakpoint.as_ref(),
 6951                                BreakpointPromptEditAction::HitCondition,
 6952                                window,
 6953                                cx,
 6954                            );
 6955                        })
 6956                        .log_err();
 6957                })
 6958        })
 6959    }
 6960
 6961    fn render_breakpoint(
 6962        &self,
 6963        position: Anchor,
 6964        row: DisplayRow,
 6965        breakpoint: &Breakpoint,
 6966        cx: &mut Context<Self>,
 6967    ) -> IconButton {
 6968        let (color, icon) = {
 6969            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 6970                (false, false) => ui::IconName::DebugBreakpoint,
 6971                (true, false) => ui::IconName::DebugLogBreakpoint,
 6972                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 6973                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 6974            };
 6975
 6976            let color = if self
 6977                .gutter_breakpoint_indicator
 6978                .0
 6979                .is_some_and(|(point, is_visible)| is_visible && point.row() == row)
 6980            {
 6981                Color::Hint
 6982            } else {
 6983                Color::Debugger
 6984            };
 6985
 6986            (color, icon)
 6987        };
 6988
 6989        let breakpoint = Arc::from(breakpoint.clone());
 6990
 6991        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 6992            .icon_size(IconSize::XSmall)
 6993            .size(ui::ButtonSize::None)
 6994            .icon_color(color)
 6995            .style(ButtonStyle::Transparent)
 6996            .on_click(cx.listener({
 6997                let breakpoint = breakpoint.clone();
 6998
 6999                move |editor, event: &ClickEvent, window, cx| {
 7000                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7001                        BreakpointEditAction::InvertState
 7002                    } else {
 7003                        BreakpointEditAction::Toggle
 7004                    };
 7005
 7006                    window.focus(&editor.focus_handle(cx));
 7007                    editor.edit_breakpoint_at_anchor(
 7008                        position,
 7009                        breakpoint.as_ref().clone(),
 7010                        edit_action,
 7011                        cx,
 7012                    );
 7013                }
 7014            }))
 7015            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7016                editor.set_breakpoint_context_menu(
 7017                    row,
 7018                    Some(position),
 7019                    event.down.position,
 7020                    window,
 7021                    cx,
 7022                );
 7023            }))
 7024    }
 7025
 7026    fn build_tasks_context(
 7027        project: &Entity<Project>,
 7028        buffer: &Entity<Buffer>,
 7029        buffer_row: u32,
 7030        tasks: &Arc<RunnableTasks>,
 7031        cx: &mut Context<Self>,
 7032    ) -> Task<Option<task::TaskContext>> {
 7033        let position = Point::new(buffer_row, tasks.column);
 7034        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7035        let location = Location {
 7036            buffer: buffer.clone(),
 7037            range: range_start..range_start,
 7038        };
 7039        // Fill in the environmental variables from the tree-sitter captures
 7040        let mut captured_task_variables = TaskVariables::default();
 7041        for (capture_name, value) in tasks.extra_variables.clone() {
 7042            captured_task_variables.insert(
 7043                task::VariableName::Custom(capture_name.into()),
 7044                value.clone(),
 7045            );
 7046        }
 7047        project.update(cx, |project, cx| {
 7048            project.task_store().update(cx, |task_store, cx| {
 7049                task_store.task_context_for_location(captured_task_variables, location, cx)
 7050            })
 7051        })
 7052    }
 7053
 7054    pub fn spawn_nearest_task(
 7055        &mut self,
 7056        action: &SpawnNearestTask,
 7057        window: &mut Window,
 7058        cx: &mut Context<Self>,
 7059    ) {
 7060        let Some((workspace, _)) = self.workspace.clone() else {
 7061            return;
 7062        };
 7063        let Some(project) = self.project.clone() else {
 7064            return;
 7065        };
 7066
 7067        // Try to find a closest, enclosing node using tree-sitter that has a
 7068        // task
 7069        let Some((buffer, buffer_row, tasks)) = self
 7070            .find_enclosing_node_task(cx)
 7071            // Or find the task that's closest in row-distance.
 7072            .or_else(|| self.find_closest_task(cx))
 7073        else {
 7074            return;
 7075        };
 7076
 7077        let reveal_strategy = action.reveal;
 7078        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7079        cx.spawn_in(window, async move |_, cx| {
 7080            let context = task_context.await?;
 7081            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7082
 7083            let resolved = &mut resolved_task.resolved;
 7084            resolved.reveal = reveal_strategy;
 7085
 7086            workspace
 7087                .update_in(cx, |workspace, window, cx| {
 7088                    workspace.schedule_resolved_task(
 7089                        task_source_kind,
 7090                        resolved_task,
 7091                        false,
 7092                        window,
 7093                        cx,
 7094                    );
 7095                })
 7096                .ok()
 7097        })
 7098        .detach();
 7099    }
 7100
 7101    fn find_closest_task(
 7102        &mut self,
 7103        cx: &mut Context<Self>,
 7104    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7105        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7106
 7107        let ((buffer_id, row), tasks) = self
 7108            .tasks
 7109            .iter()
 7110            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7111
 7112        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7113        let tasks = Arc::new(tasks.to_owned());
 7114        Some((buffer, *row, tasks))
 7115    }
 7116
 7117    fn find_enclosing_node_task(
 7118        &mut self,
 7119        cx: &mut Context<Self>,
 7120    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7121        let snapshot = self.buffer.read(cx).snapshot(cx);
 7122        let offset = self.selections.newest::<usize>(cx).head();
 7123        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7124        let buffer_id = excerpt.buffer().remote_id();
 7125
 7126        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7127        let mut cursor = layer.node().walk();
 7128
 7129        while cursor.goto_first_child_for_byte(offset).is_some() {
 7130            if cursor.node().end_byte() == offset {
 7131                cursor.goto_next_sibling();
 7132            }
 7133        }
 7134
 7135        // Ascend to the smallest ancestor that contains the range and has a task.
 7136        loop {
 7137            let node = cursor.node();
 7138            let node_range = node.byte_range();
 7139            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7140
 7141            // Check if this node contains our offset
 7142            if node_range.start <= offset && node_range.end >= offset {
 7143                // If it contains offset, check for task
 7144                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7145                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7146                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7147                }
 7148            }
 7149
 7150            if !cursor.goto_parent() {
 7151                break;
 7152            }
 7153        }
 7154        None
 7155    }
 7156
 7157    fn render_run_indicator(
 7158        &self,
 7159        _style: &EditorStyle,
 7160        is_active: bool,
 7161        row: DisplayRow,
 7162        breakpoint: Option<(Anchor, Breakpoint)>,
 7163        cx: &mut Context<Self>,
 7164    ) -> IconButton {
 7165        let color = Color::Muted;
 7166        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 7167
 7168        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7169            .shape(ui::IconButtonShape::Square)
 7170            .icon_size(IconSize::XSmall)
 7171            .icon_color(color)
 7172            .toggle_state(is_active)
 7173            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7174                let quick_launch = e.down.button == MouseButton::Left;
 7175                window.focus(&editor.focus_handle(cx));
 7176                editor.toggle_code_actions(
 7177                    &ToggleCodeActions {
 7178                        deployed_from_indicator: Some(row),
 7179                        quick_launch,
 7180                    },
 7181                    window,
 7182                    cx,
 7183                );
 7184            }))
 7185            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7186                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7187            }))
 7188    }
 7189
 7190    pub fn context_menu_visible(&self) -> bool {
 7191        !self.edit_prediction_preview_is_active()
 7192            && self
 7193                .context_menu
 7194                .borrow()
 7195                .as_ref()
 7196                .map_or(false, |menu| menu.visible())
 7197    }
 7198
 7199    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7200        self.context_menu
 7201            .borrow()
 7202            .as_ref()
 7203            .map(|menu| menu.origin())
 7204    }
 7205
 7206    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7207        self.context_menu_options = Some(options);
 7208    }
 7209
 7210    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7211    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7212
 7213    fn render_edit_prediction_popover(
 7214        &mut self,
 7215        text_bounds: &Bounds<Pixels>,
 7216        content_origin: gpui::Point<Pixels>,
 7217        editor_snapshot: &EditorSnapshot,
 7218        visible_row_range: Range<DisplayRow>,
 7219        scroll_top: f32,
 7220        scroll_bottom: f32,
 7221        line_layouts: &[LineWithInvisibles],
 7222        line_height: Pixels,
 7223        scroll_pixel_position: gpui::Point<Pixels>,
 7224        newest_selection_head: Option<DisplayPoint>,
 7225        editor_width: Pixels,
 7226        style: &EditorStyle,
 7227        window: &mut Window,
 7228        cx: &mut App,
 7229    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7230        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7231
 7232        if self.edit_prediction_visible_in_cursor_popover(true) {
 7233            return None;
 7234        }
 7235
 7236        match &active_inline_completion.completion {
 7237            InlineCompletion::Move { target, .. } => {
 7238                let target_display_point = target.to_display_point(editor_snapshot);
 7239
 7240                if self.edit_prediction_requires_modifier() {
 7241                    if !self.edit_prediction_preview_is_active() {
 7242                        return None;
 7243                    }
 7244
 7245                    self.render_edit_prediction_modifier_jump_popover(
 7246                        text_bounds,
 7247                        content_origin,
 7248                        visible_row_range,
 7249                        line_layouts,
 7250                        line_height,
 7251                        scroll_pixel_position,
 7252                        newest_selection_head,
 7253                        target_display_point,
 7254                        window,
 7255                        cx,
 7256                    )
 7257                } else {
 7258                    self.render_edit_prediction_eager_jump_popover(
 7259                        text_bounds,
 7260                        content_origin,
 7261                        editor_snapshot,
 7262                        visible_row_range,
 7263                        scroll_top,
 7264                        scroll_bottom,
 7265                        line_height,
 7266                        scroll_pixel_position,
 7267                        target_display_point,
 7268                        editor_width,
 7269                        window,
 7270                        cx,
 7271                    )
 7272                }
 7273            }
 7274            InlineCompletion::Edit {
 7275                display_mode: EditDisplayMode::Inline,
 7276                ..
 7277            } => None,
 7278            InlineCompletion::Edit {
 7279                display_mode: EditDisplayMode::TabAccept,
 7280                edits,
 7281                ..
 7282            } => {
 7283                let range = &edits.first()?.0;
 7284                let target_display_point = range.end.to_display_point(editor_snapshot);
 7285
 7286                self.render_edit_prediction_end_of_line_popover(
 7287                    "Accept",
 7288                    editor_snapshot,
 7289                    visible_row_range,
 7290                    target_display_point,
 7291                    line_height,
 7292                    scroll_pixel_position,
 7293                    content_origin,
 7294                    editor_width,
 7295                    window,
 7296                    cx,
 7297                )
 7298            }
 7299            InlineCompletion::Edit {
 7300                edits,
 7301                edit_preview,
 7302                display_mode: EditDisplayMode::DiffPopover,
 7303                snapshot,
 7304            } => self.render_edit_prediction_diff_popover(
 7305                text_bounds,
 7306                content_origin,
 7307                editor_snapshot,
 7308                visible_row_range,
 7309                line_layouts,
 7310                line_height,
 7311                scroll_pixel_position,
 7312                newest_selection_head,
 7313                editor_width,
 7314                style,
 7315                edits,
 7316                edit_preview,
 7317                snapshot,
 7318                window,
 7319                cx,
 7320            ),
 7321        }
 7322    }
 7323
 7324    fn render_edit_prediction_modifier_jump_popover(
 7325        &mut self,
 7326        text_bounds: &Bounds<Pixels>,
 7327        content_origin: gpui::Point<Pixels>,
 7328        visible_row_range: Range<DisplayRow>,
 7329        line_layouts: &[LineWithInvisibles],
 7330        line_height: Pixels,
 7331        scroll_pixel_position: gpui::Point<Pixels>,
 7332        newest_selection_head: Option<DisplayPoint>,
 7333        target_display_point: DisplayPoint,
 7334        window: &mut Window,
 7335        cx: &mut App,
 7336    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7337        let scrolled_content_origin =
 7338            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7339
 7340        const SCROLL_PADDING_Y: Pixels = px(12.);
 7341
 7342        if target_display_point.row() < visible_row_range.start {
 7343            return self.render_edit_prediction_scroll_popover(
 7344                |_| SCROLL_PADDING_Y,
 7345                IconName::ArrowUp,
 7346                visible_row_range,
 7347                line_layouts,
 7348                newest_selection_head,
 7349                scrolled_content_origin,
 7350                window,
 7351                cx,
 7352            );
 7353        } else if target_display_point.row() >= visible_row_range.end {
 7354            return self.render_edit_prediction_scroll_popover(
 7355                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7356                IconName::ArrowDown,
 7357                visible_row_range,
 7358                line_layouts,
 7359                newest_selection_head,
 7360                scrolled_content_origin,
 7361                window,
 7362                cx,
 7363            );
 7364        }
 7365
 7366        const POLE_WIDTH: Pixels = px(2.);
 7367
 7368        let line_layout =
 7369            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7370        let target_column = target_display_point.column() as usize;
 7371
 7372        let target_x = line_layout.x_for_index(target_column);
 7373        let target_y =
 7374            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7375
 7376        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7377
 7378        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7379        border_color.l += 0.001;
 7380
 7381        let mut element = v_flex()
 7382            .items_end()
 7383            .when(flag_on_right, |el| el.items_start())
 7384            .child(if flag_on_right {
 7385                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7386                    .rounded_bl(px(0.))
 7387                    .rounded_tl(px(0.))
 7388                    .border_l_2()
 7389                    .border_color(border_color)
 7390            } else {
 7391                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7392                    .rounded_br(px(0.))
 7393                    .rounded_tr(px(0.))
 7394                    .border_r_2()
 7395                    .border_color(border_color)
 7396            })
 7397            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7398            .into_any();
 7399
 7400        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7401
 7402        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7403            - point(
 7404                if flag_on_right {
 7405                    POLE_WIDTH
 7406                } else {
 7407                    size.width - POLE_WIDTH
 7408                },
 7409                size.height - line_height,
 7410            );
 7411
 7412        origin.x = origin.x.max(content_origin.x);
 7413
 7414        element.prepaint_at(origin, window, cx);
 7415
 7416        Some((element, origin))
 7417    }
 7418
 7419    fn render_edit_prediction_scroll_popover(
 7420        &mut self,
 7421        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7422        scroll_icon: IconName,
 7423        visible_row_range: Range<DisplayRow>,
 7424        line_layouts: &[LineWithInvisibles],
 7425        newest_selection_head: Option<DisplayPoint>,
 7426        scrolled_content_origin: gpui::Point<Pixels>,
 7427        window: &mut Window,
 7428        cx: &mut App,
 7429    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7430        let mut element = self
 7431            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7432            .into_any();
 7433
 7434        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7435
 7436        let cursor = newest_selection_head?;
 7437        let cursor_row_layout =
 7438            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7439        let cursor_column = cursor.column() as usize;
 7440
 7441        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7442
 7443        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7444
 7445        element.prepaint_at(origin, window, cx);
 7446        Some((element, origin))
 7447    }
 7448
 7449    fn render_edit_prediction_eager_jump_popover(
 7450        &mut self,
 7451        text_bounds: &Bounds<Pixels>,
 7452        content_origin: gpui::Point<Pixels>,
 7453        editor_snapshot: &EditorSnapshot,
 7454        visible_row_range: Range<DisplayRow>,
 7455        scroll_top: f32,
 7456        scroll_bottom: f32,
 7457        line_height: Pixels,
 7458        scroll_pixel_position: gpui::Point<Pixels>,
 7459        target_display_point: DisplayPoint,
 7460        editor_width: Pixels,
 7461        window: &mut Window,
 7462        cx: &mut App,
 7463    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7464        if target_display_point.row().as_f32() < scroll_top {
 7465            let mut element = self
 7466                .render_edit_prediction_line_popover(
 7467                    "Jump to Edit",
 7468                    Some(IconName::ArrowUp),
 7469                    window,
 7470                    cx,
 7471                )?
 7472                .into_any();
 7473
 7474            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7475            let offset = point(
 7476                (text_bounds.size.width - size.width) / 2.,
 7477                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7478            );
 7479
 7480            let origin = text_bounds.origin + offset;
 7481            element.prepaint_at(origin, window, cx);
 7482            Some((element, origin))
 7483        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7484            let mut element = self
 7485                .render_edit_prediction_line_popover(
 7486                    "Jump to Edit",
 7487                    Some(IconName::ArrowDown),
 7488                    window,
 7489                    cx,
 7490                )?
 7491                .into_any();
 7492
 7493            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7494            let offset = point(
 7495                (text_bounds.size.width - size.width) / 2.,
 7496                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7497            );
 7498
 7499            let origin = text_bounds.origin + offset;
 7500            element.prepaint_at(origin, window, cx);
 7501            Some((element, origin))
 7502        } else {
 7503            self.render_edit_prediction_end_of_line_popover(
 7504                "Jump to Edit",
 7505                editor_snapshot,
 7506                visible_row_range,
 7507                target_display_point,
 7508                line_height,
 7509                scroll_pixel_position,
 7510                content_origin,
 7511                editor_width,
 7512                window,
 7513                cx,
 7514            )
 7515        }
 7516    }
 7517
 7518    fn render_edit_prediction_end_of_line_popover(
 7519        self: &mut Editor,
 7520        label: &'static str,
 7521        editor_snapshot: &EditorSnapshot,
 7522        visible_row_range: Range<DisplayRow>,
 7523        target_display_point: DisplayPoint,
 7524        line_height: Pixels,
 7525        scroll_pixel_position: gpui::Point<Pixels>,
 7526        content_origin: gpui::Point<Pixels>,
 7527        editor_width: Pixels,
 7528        window: &mut Window,
 7529        cx: &mut App,
 7530    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7531        let target_line_end = DisplayPoint::new(
 7532            target_display_point.row(),
 7533            editor_snapshot.line_len(target_display_point.row()),
 7534        );
 7535
 7536        let mut element = self
 7537            .render_edit_prediction_line_popover(label, None, window, cx)?
 7538            .into_any();
 7539
 7540        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7541
 7542        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7543
 7544        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7545        let mut origin = start_point
 7546            + line_origin
 7547            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7548        origin.x = origin.x.max(content_origin.x);
 7549
 7550        let max_x = content_origin.x + editor_width - size.width;
 7551
 7552        if origin.x > max_x {
 7553            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7554
 7555            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7556                origin.y += offset;
 7557                IconName::ArrowUp
 7558            } else {
 7559                origin.y -= offset;
 7560                IconName::ArrowDown
 7561            };
 7562
 7563            element = self
 7564                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7565                .into_any();
 7566
 7567            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7568
 7569            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7570        }
 7571
 7572        element.prepaint_at(origin, window, cx);
 7573        Some((element, origin))
 7574    }
 7575
 7576    fn render_edit_prediction_diff_popover(
 7577        self: &Editor,
 7578        text_bounds: &Bounds<Pixels>,
 7579        content_origin: gpui::Point<Pixels>,
 7580        editor_snapshot: &EditorSnapshot,
 7581        visible_row_range: Range<DisplayRow>,
 7582        line_layouts: &[LineWithInvisibles],
 7583        line_height: Pixels,
 7584        scroll_pixel_position: gpui::Point<Pixels>,
 7585        newest_selection_head: Option<DisplayPoint>,
 7586        editor_width: Pixels,
 7587        style: &EditorStyle,
 7588        edits: &Vec<(Range<Anchor>, String)>,
 7589        edit_preview: &Option<language::EditPreview>,
 7590        snapshot: &language::BufferSnapshot,
 7591        window: &mut Window,
 7592        cx: &mut App,
 7593    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7594        let edit_start = edits
 7595            .first()
 7596            .unwrap()
 7597            .0
 7598            .start
 7599            .to_display_point(editor_snapshot);
 7600        let edit_end = edits
 7601            .last()
 7602            .unwrap()
 7603            .0
 7604            .end
 7605            .to_display_point(editor_snapshot);
 7606
 7607        let is_visible = visible_row_range.contains(&edit_start.row())
 7608            || visible_row_range.contains(&edit_end.row());
 7609        if !is_visible {
 7610            return None;
 7611        }
 7612
 7613        let highlighted_edits =
 7614            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7615
 7616        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7617        let line_count = highlighted_edits.text.lines().count();
 7618
 7619        const BORDER_WIDTH: Pixels = px(1.);
 7620
 7621        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7622        let has_keybind = keybind.is_some();
 7623
 7624        let mut element = h_flex()
 7625            .items_start()
 7626            .child(
 7627                h_flex()
 7628                    .bg(cx.theme().colors().editor_background)
 7629                    .border(BORDER_WIDTH)
 7630                    .shadow_sm()
 7631                    .border_color(cx.theme().colors().border)
 7632                    .rounded_l_lg()
 7633                    .when(line_count > 1, |el| el.rounded_br_lg())
 7634                    .pr_1()
 7635                    .child(styled_text),
 7636            )
 7637            .child(
 7638                h_flex()
 7639                    .h(line_height + BORDER_WIDTH * 2.)
 7640                    .px_1p5()
 7641                    .gap_1()
 7642                    // Workaround: For some reason, there's a gap if we don't do this
 7643                    .ml(-BORDER_WIDTH)
 7644                    .shadow(smallvec![gpui::BoxShadow {
 7645                        color: gpui::black().opacity(0.05),
 7646                        offset: point(px(1.), px(1.)),
 7647                        blur_radius: px(2.),
 7648                        spread_radius: px(0.),
 7649                    }])
 7650                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7651                    .border(BORDER_WIDTH)
 7652                    .border_color(cx.theme().colors().border)
 7653                    .rounded_r_lg()
 7654                    .id("edit_prediction_diff_popover_keybind")
 7655                    .when(!has_keybind, |el| {
 7656                        let status_colors = cx.theme().status();
 7657
 7658                        el.bg(status_colors.error_background)
 7659                            .border_color(status_colors.error.opacity(0.6))
 7660                            .child(Icon::new(IconName::Info).color(Color::Error))
 7661                            .cursor_default()
 7662                            .hoverable_tooltip(move |_window, cx| {
 7663                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7664                            })
 7665                    })
 7666                    .children(keybind),
 7667            )
 7668            .into_any();
 7669
 7670        let longest_row =
 7671            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7672        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7673            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7674        } else {
 7675            layout_line(
 7676                longest_row,
 7677                editor_snapshot,
 7678                style,
 7679                editor_width,
 7680                |_| false,
 7681                window,
 7682                cx,
 7683            )
 7684            .width
 7685        };
 7686
 7687        let viewport_bounds =
 7688            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7689                right: -EditorElement::SCROLLBAR_WIDTH,
 7690                ..Default::default()
 7691            });
 7692
 7693        let x_after_longest =
 7694            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 7695                - scroll_pixel_position.x;
 7696
 7697        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7698
 7699        // Fully visible if it can be displayed within the window (allow overlapping other
 7700        // panes). However, this is only allowed if the popover starts within text_bounds.
 7701        let can_position_to_the_right = x_after_longest < text_bounds.right()
 7702            && x_after_longest + element_bounds.width < viewport_bounds.right();
 7703
 7704        let mut origin = if can_position_to_the_right {
 7705            point(
 7706                x_after_longest,
 7707                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 7708                    - scroll_pixel_position.y,
 7709            )
 7710        } else {
 7711            let cursor_row = newest_selection_head.map(|head| head.row());
 7712            let above_edit = edit_start
 7713                .row()
 7714                .0
 7715                .checked_sub(line_count as u32)
 7716                .map(DisplayRow);
 7717            let below_edit = Some(edit_end.row() + 1);
 7718            let above_cursor =
 7719                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 7720            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 7721
 7722            // Place the edit popover adjacent to the edit if there is a location
 7723            // available that is onscreen and does not obscure the cursor. Otherwise,
 7724            // place it adjacent to the cursor.
 7725            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 7726                .into_iter()
 7727                .flatten()
 7728                .find(|&start_row| {
 7729                    let end_row = start_row + line_count as u32;
 7730                    visible_row_range.contains(&start_row)
 7731                        && visible_row_range.contains(&end_row)
 7732                        && cursor_row.map_or(true, |cursor_row| {
 7733                            !((start_row..end_row).contains(&cursor_row))
 7734                        })
 7735                })?;
 7736
 7737            content_origin
 7738                + point(
 7739                    -scroll_pixel_position.x,
 7740                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 7741                )
 7742        };
 7743
 7744        origin.x -= BORDER_WIDTH;
 7745
 7746        window.defer_draw(element, origin, 1);
 7747
 7748        // Do not return an element, since it will already be drawn due to defer_draw.
 7749        None
 7750    }
 7751
 7752    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 7753        px(30.)
 7754    }
 7755
 7756    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 7757        if self.read_only(cx) {
 7758            cx.theme().players().read_only()
 7759        } else {
 7760            self.style.as_ref().unwrap().local_player
 7761        }
 7762    }
 7763
 7764    fn render_edit_prediction_accept_keybind(
 7765        &self,
 7766        window: &mut Window,
 7767        cx: &App,
 7768    ) -> Option<AnyElement> {
 7769        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 7770        let accept_keystroke = accept_binding.keystroke()?;
 7771
 7772        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7773
 7774        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 7775            Color::Accent
 7776        } else {
 7777            Color::Muted
 7778        };
 7779
 7780        h_flex()
 7781            .px_0p5()
 7782            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 7783            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7784            .text_size(TextSize::XSmall.rems(cx))
 7785            .child(h_flex().children(ui::render_modifiers(
 7786                &accept_keystroke.modifiers,
 7787                PlatformStyle::platform(),
 7788                Some(modifiers_color),
 7789                Some(IconSize::XSmall.rems().into()),
 7790                true,
 7791            )))
 7792            .when(is_platform_style_mac, |parent| {
 7793                parent.child(accept_keystroke.key.clone())
 7794            })
 7795            .when(!is_platform_style_mac, |parent| {
 7796                parent.child(
 7797                    Key::new(
 7798                        util::capitalize(&accept_keystroke.key),
 7799                        Some(Color::Default),
 7800                    )
 7801                    .size(Some(IconSize::XSmall.rems().into())),
 7802                )
 7803            })
 7804            .into_any()
 7805            .into()
 7806    }
 7807
 7808    fn render_edit_prediction_line_popover(
 7809        &self,
 7810        label: impl Into<SharedString>,
 7811        icon: Option<IconName>,
 7812        window: &mut Window,
 7813        cx: &App,
 7814    ) -> Option<Stateful<Div>> {
 7815        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 7816
 7817        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7818        let has_keybind = keybind.is_some();
 7819
 7820        let result = h_flex()
 7821            .id("ep-line-popover")
 7822            .py_0p5()
 7823            .pl_1()
 7824            .pr(padding_right)
 7825            .gap_1()
 7826            .rounded_md()
 7827            .border_1()
 7828            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7829            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 7830            .shadow_sm()
 7831            .when(!has_keybind, |el| {
 7832                let status_colors = cx.theme().status();
 7833
 7834                el.bg(status_colors.error_background)
 7835                    .border_color(status_colors.error.opacity(0.6))
 7836                    .pl_2()
 7837                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 7838                    .cursor_default()
 7839                    .hoverable_tooltip(move |_window, cx| {
 7840                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7841                    })
 7842            })
 7843            .children(keybind)
 7844            .child(
 7845                Label::new(label)
 7846                    .size(LabelSize::Small)
 7847                    .when(!has_keybind, |el| {
 7848                        el.color(cx.theme().status().error.into()).strikethrough()
 7849                    }),
 7850            )
 7851            .when(!has_keybind, |el| {
 7852                el.child(
 7853                    h_flex().ml_1().child(
 7854                        Icon::new(IconName::Info)
 7855                            .size(IconSize::Small)
 7856                            .color(cx.theme().status().error.into()),
 7857                    ),
 7858                )
 7859            })
 7860            .when_some(icon, |element, icon| {
 7861                element.child(
 7862                    div()
 7863                        .mt(px(1.5))
 7864                        .child(Icon::new(icon).size(IconSize::Small)),
 7865                )
 7866            });
 7867
 7868        Some(result)
 7869    }
 7870
 7871    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 7872        let accent_color = cx.theme().colors().text_accent;
 7873        let editor_bg_color = cx.theme().colors().editor_background;
 7874        editor_bg_color.blend(accent_color.opacity(0.1))
 7875    }
 7876
 7877    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 7878        let accent_color = cx.theme().colors().text_accent;
 7879        let editor_bg_color = cx.theme().colors().editor_background;
 7880        editor_bg_color.blend(accent_color.opacity(0.6))
 7881    }
 7882
 7883    fn render_edit_prediction_cursor_popover(
 7884        &self,
 7885        min_width: Pixels,
 7886        max_width: Pixels,
 7887        cursor_point: Point,
 7888        style: &EditorStyle,
 7889        accept_keystroke: Option<&gpui::Keystroke>,
 7890        _window: &Window,
 7891        cx: &mut Context<Editor>,
 7892    ) -> Option<AnyElement> {
 7893        let provider = self.edit_prediction_provider.as_ref()?;
 7894
 7895        if provider.provider.needs_terms_acceptance(cx) {
 7896            return Some(
 7897                h_flex()
 7898                    .min_w(min_width)
 7899                    .flex_1()
 7900                    .px_2()
 7901                    .py_1()
 7902                    .gap_3()
 7903                    .elevation_2(cx)
 7904                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 7905                    .id("accept-terms")
 7906                    .cursor_pointer()
 7907                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 7908                    .on_click(cx.listener(|this, _event, window, cx| {
 7909                        cx.stop_propagation();
 7910                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 7911                        window.dispatch_action(
 7912                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 7913                            cx,
 7914                        );
 7915                    }))
 7916                    .child(
 7917                        h_flex()
 7918                            .flex_1()
 7919                            .gap_2()
 7920                            .child(Icon::new(IconName::ZedPredict))
 7921                            .child(Label::new("Accept Terms of Service"))
 7922                            .child(div().w_full())
 7923                            .child(
 7924                                Icon::new(IconName::ArrowUpRight)
 7925                                    .color(Color::Muted)
 7926                                    .size(IconSize::Small),
 7927                            )
 7928                            .into_any_element(),
 7929                    )
 7930                    .into_any(),
 7931            );
 7932        }
 7933
 7934        let is_refreshing = provider.provider.is_refreshing(cx);
 7935
 7936        fn pending_completion_container() -> Div {
 7937            h_flex()
 7938                .h_full()
 7939                .flex_1()
 7940                .gap_2()
 7941                .child(Icon::new(IconName::ZedPredict))
 7942        }
 7943
 7944        let completion = match &self.active_inline_completion {
 7945            Some(prediction) => {
 7946                if !self.has_visible_completions_menu() {
 7947                    const RADIUS: Pixels = px(6.);
 7948                    const BORDER_WIDTH: Pixels = px(1.);
 7949
 7950                    return Some(
 7951                        h_flex()
 7952                            .elevation_2(cx)
 7953                            .border(BORDER_WIDTH)
 7954                            .border_color(cx.theme().colors().border)
 7955                            .when(accept_keystroke.is_none(), |el| {
 7956                                el.border_color(cx.theme().status().error)
 7957                            })
 7958                            .rounded(RADIUS)
 7959                            .rounded_tl(px(0.))
 7960                            .overflow_hidden()
 7961                            .child(div().px_1p5().child(match &prediction.completion {
 7962                                InlineCompletion::Move { target, snapshot } => {
 7963                                    use text::ToPoint as _;
 7964                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 7965                                    {
 7966                                        Icon::new(IconName::ZedPredictDown)
 7967                                    } else {
 7968                                        Icon::new(IconName::ZedPredictUp)
 7969                                    }
 7970                                }
 7971                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 7972                            }))
 7973                            .child(
 7974                                h_flex()
 7975                                    .gap_1()
 7976                                    .py_1()
 7977                                    .px_2()
 7978                                    .rounded_r(RADIUS - BORDER_WIDTH)
 7979                                    .border_l_1()
 7980                                    .border_color(cx.theme().colors().border)
 7981                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7982                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 7983                                        el.child(
 7984                                            Label::new("Hold")
 7985                                                .size(LabelSize::Small)
 7986                                                .when(accept_keystroke.is_none(), |el| {
 7987                                                    el.strikethrough()
 7988                                                })
 7989                                                .line_height_style(LineHeightStyle::UiLabel),
 7990                                        )
 7991                                    })
 7992                                    .id("edit_prediction_cursor_popover_keybind")
 7993                                    .when(accept_keystroke.is_none(), |el| {
 7994                                        let status_colors = cx.theme().status();
 7995
 7996                                        el.bg(status_colors.error_background)
 7997                                            .border_color(status_colors.error.opacity(0.6))
 7998                                            .child(Icon::new(IconName::Info).color(Color::Error))
 7999                                            .cursor_default()
 8000                                            .hoverable_tooltip(move |_window, cx| {
 8001                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8002                                                    .into()
 8003                                            })
 8004                                    })
 8005                                    .when_some(
 8006                                        accept_keystroke.as_ref(),
 8007                                        |el, accept_keystroke| {
 8008                                            el.child(h_flex().children(ui::render_modifiers(
 8009                                                &accept_keystroke.modifiers,
 8010                                                PlatformStyle::platform(),
 8011                                                Some(Color::Default),
 8012                                                Some(IconSize::XSmall.rems().into()),
 8013                                                false,
 8014                                            )))
 8015                                        },
 8016                                    ),
 8017                            )
 8018                            .into_any(),
 8019                    );
 8020                }
 8021
 8022                self.render_edit_prediction_cursor_popover_preview(
 8023                    prediction,
 8024                    cursor_point,
 8025                    style,
 8026                    cx,
 8027                )?
 8028            }
 8029
 8030            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8031                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8032                    stale_completion,
 8033                    cursor_point,
 8034                    style,
 8035                    cx,
 8036                )?,
 8037
 8038                None => {
 8039                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8040                }
 8041            },
 8042
 8043            None => pending_completion_container().child(Label::new("No Prediction")),
 8044        };
 8045
 8046        let completion = if is_refreshing {
 8047            completion
 8048                .with_animation(
 8049                    "loading-completion",
 8050                    Animation::new(Duration::from_secs(2))
 8051                        .repeat()
 8052                        .with_easing(pulsating_between(0.4, 0.8)),
 8053                    |label, delta| label.opacity(delta),
 8054                )
 8055                .into_any_element()
 8056        } else {
 8057            completion.into_any_element()
 8058        };
 8059
 8060        let has_completion = self.active_inline_completion.is_some();
 8061
 8062        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8063        Some(
 8064            h_flex()
 8065                .min_w(min_width)
 8066                .max_w(max_width)
 8067                .flex_1()
 8068                .elevation_2(cx)
 8069                .border_color(cx.theme().colors().border)
 8070                .child(
 8071                    div()
 8072                        .flex_1()
 8073                        .py_1()
 8074                        .px_2()
 8075                        .overflow_hidden()
 8076                        .child(completion),
 8077                )
 8078                .when_some(accept_keystroke, |el, accept_keystroke| {
 8079                    if !accept_keystroke.modifiers.modified() {
 8080                        return el;
 8081                    }
 8082
 8083                    el.child(
 8084                        h_flex()
 8085                            .h_full()
 8086                            .border_l_1()
 8087                            .rounded_r_lg()
 8088                            .border_color(cx.theme().colors().border)
 8089                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8090                            .gap_1()
 8091                            .py_1()
 8092                            .px_2()
 8093                            .child(
 8094                                h_flex()
 8095                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8096                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8097                                    .child(h_flex().children(ui::render_modifiers(
 8098                                        &accept_keystroke.modifiers,
 8099                                        PlatformStyle::platform(),
 8100                                        Some(if !has_completion {
 8101                                            Color::Muted
 8102                                        } else {
 8103                                            Color::Default
 8104                                        }),
 8105                                        None,
 8106                                        false,
 8107                                    ))),
 8108                            )
 8109                            .child(Label::new("Preview").into_any_element())
 8110                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8111                    )
 8112                })
 8113                .into_any(),
 8114        )
 8115    }
 8116
 8117    fn render_edit_prediction_cursor_popover_preview(
 8118        &self,
 8119        completion: &InlineCompletionState,
 8120        cursor_point: Point,
 8121        style: &EditorStyle,
 8122        cx: &mut Context<Editor>,
 8123    ) -> Option<Div> {
 8124        use text::ToPoint as _;
 8125
 8126        fn render_relative_row_jump(
 8127            prefix: impl Into<String>,
 8128            current_row: u32,
 8129            target_row: u32,
 8130        ) -> Div {
 8131            let (row_diff, arrow) = if target_row < current_row {
 8132                (current_row - target_row, IconName::ArrowUp)
 8133            } else {
 8134                (target_row - current_row, IconName::ArrowDown)
 8135            };
 8136
 8137            h_flex()
 8138                .child(
 8139                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8140                        .color(Color::Muted)
 8141                        .size(LabelSize::Small),
 8142                )
 8143                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8144        }
 8145
 8146        match &completion.completion {
 8147            InlineCompletion::Move {
 8148                target, snapshot, ..
 8149            } => Some(
 8150                h_flex()
 8151                    .px_2()
 8152                    .gap_2()
 8153                    .flex_1()
 8154                    .child(
 8155                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8156                            Icon::new(IconName::ZedPredictDown)
 8157                        } else {
 8158                            Icon::new(IconName::ZedPredictUp)
 8159                        },
 8160                    )
 8161                    .child(Label::new("Jump to Edit")),
 8162            ),
 8163
 8164            InlineCompletion::Edit {
 8165                edits,
 8166                edit_preview,
 8167                snapshot,
 8168                display_mode: _,
 8169            } => {
 8170                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8171
 8172                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8173                    &snapshot,
 8174                    &edits,
 8175                    edit_preview.as_ref()?,
 8176                    true,
 8177                    cx,
 8178                )
 8179                .first_line_preview();
 8180
 8181                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8182                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8183
 8184                let preview = h_flex()
 8185                    .gap_1()
 8186                    .min_w_16()
 8187                    .child(styled_text)
 8188                    .when(has_more_lines, |parent| parent.child(""));
 8189
 8190                let left = if first_edit_row != cursor_point.row {
 8191                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8192                        .into_any_element()
 8193                } else {
 8194                    Icon::new(IconName::ZedPredict).into_any_element()
 8195                };
 8196
 8197                Some(
 8198                    h_flex()
 8199                        .h_full()
 8200                        .flex_1()
 8201                        .gap_2()
 8202                        .pr_1()
 8203                        .overflow_x_hidden()
 8204                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8205                        .child(left)
 8206                        .child(preview),
 8207                )
 8208            }
 8209        }
 8210    }
 8211
 8212    fn render_context_menu(
 8213        &self,
 8214        style: &EditorStyle,
 8215        max_height_in_lines: u32,
 8216        window: &mut Window,
 8217        cx: &mut Context<Editor>,
 8218    ) -> Option<AnyElement> {
 8219        let menu = self.context_menu.borrow();
 8220        let menu = menu.as_ref()?;
 8221        if !menu.visible() {
 8222            return None;
 8223        };
 8224        Some(menu.render(style, max_height_in_lines, window, cx))
 8225    }
 8226
 8227    fn render_context_menu_aside(
 8228        &mut self,
 8229        max_size: Size<Pixels>,
 8230        window: &mut Window,
 8231        cx: &mut Context<Editor>,
 8232    ) -> Option<AnyElement> {
 8233        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8234            if menu.visible() {
 8235                menu.render_aside(self, max_size, window, cx)
 8236            } else {
 8237                None
 8238            }
 8239        })
 8240    }
 8241
 8242    fn hide_context_menu(
 8243        &mut self,
 8244        window: &mut Window,
 8245        cx: &mut Context<Self>,
 8246    ) -> Option<CodeContextMenu> {
 8247        cx.notify();
 8248        self.completion_tasks.clear();
 8249        let context_menu = self.context_menu.borrow_mut().take();
 8250        self.stale_inline_completion_in_menu.take();
 8251        self.update_visible_inline_completion(window, cx);
 8252        context_menu
 8253    }
 8254
 8255    fn show_snippet_choices(
 8256        &mut self,
 8257        choices: &Vec<String>,
 8258        selection: Range<Anchor>,
 8259        cx: &mut Context<Self>,
 8260    ) {
 8261        if selection.start.buffer_id.is_none() {
 8262            return;
 8263        }
 8264        let buffer_id = selection.start.buffer_id.unwrap();
 8265        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8266        let id = post_inc(&mut self.next_completion_id);
 8267        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8268
 8269        if let Some(buffer) = buffer {
 8270            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8271                CompletionsMenu::new_snippet_choices(
 8272                    id,
 8273                    true,
 8274                    choices,
 8275                    selection,
 8276                    buffer,
 8277                    snippet_sort_order,
 8278                ),
 8279            ));
 8280        }
 8281    }
 8282
 8283    pub fn insert_snippet(
 8284        &mut self,
 8285        insertion_ranges: &[Range<usize>],
 8286        snippet: Snippet,
 8287        window: &mut Window,
 8288        cx: &mut Context<Self>,
 8289    ) -> Result<()> {
 8290        struct Tabstop<T> {
 8291            is_end_tabstop: bool,
 8292            ranges: Vec<Range<T>>,
 8293            choices: Option<Vec<String>>,
 8294        }
 8295
 8296        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8297            let snippet_text: Arc<str> = snippet.text.clone().into();
 8298            let edits = insertion_ranges
 8299                .iter()
 8300                .cloned()
 8301                .map(|range| (range, snippet_text.clone()));
 8302            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8303
 8304            let snapshot = &*buffer.read(cx);
 8305            let snippet = &snippet;
 8306            snippet
 8307                .tabstops
 8308                .iter()
 8309                .map(|tabstop| {
 8310                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8311                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8312                    });
 8313                    let mut tabstop_ranges = tabstop
 8314                        .ranges
 8315                        .iter()
 8316                        .flat_map(|tabstop_range| {
 8317                            let mut delta = 0_isize;
 8318                            insertion_ranges.iter().map(move |insertion_range| {
 8319                                let insertion_start = insertion_range.start as isize + delta;
 8320                                delta +=
 8321                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8322
 8323                                let start = ((insertion_start + tabstop_range.start) as usize)
 8324                                    .min(snapshot.len());
 8325                                let end = ((insertion_start + tabstop_range.end) as usize)
 8326                                    .min(snapshot.len());
 8327                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8328                            })
 8329                        })
 8330                        .collect::<Vec<_>>();
 8331                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8332
 8333                    Tabstop {
 8334                        is_end_tabstop,
 8335                        ranges: tabstop_ranges,
 8336                        choices: tabstop.choices.clone(),
 8337                    }
 8338                })
 8339                .collect::<Vec<_>>()
 8340        });
 8341        if let Some(tabstop) = tabstops.first() {
 8342            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8343                s.select_ranges(tabstop.ranges.iter().cloned());
 8344            });
 8345
 8346            if let Some(choices) = &tabstop.choices {
 8347                if let Some(selection) = tabstop.ranges.first() {
 8348                    self.show_snippet_choices(choices, selection.clone(), cx)
 8349                }
 8350            }
 8351
 8352            // If we're already at the last tabstop and it's at the end of the snippet,
 8353            // we're done, we don't need to keep the state around.
 8354            if !tabstop.is_end_tabstop {
 8355                let choices = tabstops
 8356                    .iter()
 8357                    .map(|tabstop| tabstop.choices.clone())
 8358                    .collect();
 8359
 8360                let ranges = tabstops
 8361                    .into_iter()
 8362                    .map(|tabstop| tabstop.ranges)
 8363                    .collect::<Vec<_>>();
 8364
 8365                self.snippet_stack.push(SnippetState {
 8366                    active_index: 0,
 8367                    ranges,
 8368                    choices,
 8369                });
 8370            }
 8371
 8372            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8373            if self.autoclose_regions.is_empty() {
 8374                let snapshot = self.buffer.read(cx).snapshot(cx);
 8375                for selection in &mut self.selections.all::<Point>(cx) {
 8376                    let selection_head = selection.head();
 8377                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8378                        continue;
 8379                    };
 8380
 8381                    let mut bracket_pair = None;
 8382                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8383                    let prev_chars = snapshot
 8384                        .reversed_chars_at(selection_head)
 8385                        .collect::<String>();
 8386                    for (pair, enabled) in scope.brackets() {
 8387                        if enabled
 8388                            && pair.close
 8389                            && prev_chars.starts_with(pair.start.as_str())
 8390                            && next_chars.starts_with(pair.end.as_str())
 8391                        {
 8392                            bracket_pair = Some(pair.clone());
 8393                            break;
 8394                        }
 8395                    }
 8396                    if let Some(pair) = bracket_pair {
 8397                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8398                        let autoclose_enabled =
 8399                            self.use_autoclose && snapshot_settings.use_autoclose;
 8400                        if autoclose_enabled {
 8401                            let start = snapshot.anchor_after(selection_head);
 8402                            let end = snapshot.anchor_after(selection_head);
 8403                            self.autoclose_regions.push(AutocloseRegion {
 8404                                selection_id: selection.id,
 8405                                range: start..end,
 8406                                pair,
 8407                            });
 8408                        }
 8409                    }
 8410                }
 8411            }
 8412        }
 8413        Ok(())
 8414    }
 8415
 8416    pub fn move_to_next_snippet_tabstop(
 8417        &mut self,
 8418        window: &mut Window,
 8419        cx: &mut Context<Self>,
 8420    ) -> bool {
 8421        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8422    }
 8423
 8424    pub fn move_to_prev_snippet_tabstop(
 8425        &mut self,
 8426        window: &mut Window,
 8427        cx: &mut Context<Self>,
 8428    ) -> bool {
 8429        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8430    }
 8431
 8432    pub fn move_to_snippet_tabstop(
 8433        &mut self,
 8434        bias: Bias,
 8435        window: &mut Window,
 8436        cx: &mut Context<Self>,
 8437    ) -> bool {
 8438        if let Some(mut snippet) = self.snippet_stack.pop() {
 8439            match bias {
 8440                Bias::Left => {
 8441                    if snippet.active_index > 0 {
 8442                        snippet.active_index -= 1;
 8443                    } else {
 8444                        self.snippet_stack.push(snippet);
 8445                        return false;
 8446                    }
 8447                }
 8448                Bias::Right => {
 8449                    if snippet.active_index + 1 < snippet.ranges.len() {
 8450                        snippet.active_index += 1;
 8451                    } else {
 8452                        self.snippet_stack.push(snippet);
 8453                        return false;
 8454                    }
 8455                }
 8456            }
 8457            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8458                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8459                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8460                });
 8461
 8462                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8463                    if let Some(selection) = current_ranges.first() {
 8464                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8465                    }
 8466                }
 8467
 8468                // If snippet state is not at the last tabstop, push it back on the stack
 8469                if snippet.active_index + 1 < snippet.ranges.len() {
 8470                    self.snippet_stack.push(snippet);
 8471                }
 8472                return true;
 8473            }
 8474        }
 8475
 8476        false
 8477    }
 8478
 8479    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8480        self.transact(window, cx, |this, window, cx| {
 8481            this.select_all(&SelectAll, window, cx);
 8482            this.insert("", window, cx);
 8483        });
 8484    }
 8485
 8486    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8487        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8488        self.transact(window, cx, |this, window, cx| {
 8489            this.select_autoclose_pair(window, cx);
 8490            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8491            if !this.linked_edit_ranges.is_empty() {
 8492                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8493                let snapshot = this.buffer.read(cx).snapshot(cx);
 8494
 8495                for selection in selections.iter() {
 8496                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8497                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8498                    if selection_start.buffer_id != selection_end.buffer_id {
 8499                        continue;
 8500                    }
 8501                    if let Some(ranges) =
 8502                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8503                    {
 8504                        for (buffer, entries) in ranges {
 8505                            linked_ranges.entry(buffer).or_default().extend(entries);
 8506                        }
 8507                    }
 8508                }
 8509            }
 8510
 8511            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8512            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8513            for selection in &mut selections {
 8514                if selection.is_empty() {
 8515                    let old_head = selection.head();
 8516                    let mut new_head =
 8517                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8518                            .to_point(&display_map);
 8519                    if let Some((buffer, line_buffer_range)) = display_map
 8520                        .buffer_snapshot
 8521                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8522                    {
 8523                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8524                        let indent_len = match indent_size.kind {
 8525                            IndentKind::Space => {
 8526                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8527                            }
 8528                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8529                        };
 8530                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8531                            let indent_len = indent_len.get();
 8532                            new_head = cmp::min(
 8533                                new_head,
 8534                                MultiBufferPoint::new(
 8535                                    old_head.row,
 8536                                    ((old_head.column - 1) / indent_len) * indent_len,
 8537                                ),
 8538                            );
 8539                        }
 8540                    }
 8541
 8542                    selection.set_head(new_head, SelectionGoal::None);
 8543                }
 8544            }
 8545
 8546            this.signature_help_state.set_backspace_pressed(true);
 8547            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8548                s.select(selections)
 8549            });
 8550            this.insert("", window, cx);
 8551            let empty_str: Arc<str> = Arc::from("");
 8552            for (buffer, edits) in linked_ranges {
 8553                let snapshot = buffer.read(cx).snapshot();
 8554                use text::ToPoint as TP;
 8555
 8556                let edits = edits
 8557                    .into_iter()
 8558                    .map(|range| {
 8559                        let end_point = TP::to_point(&range.end, &snapshot);
 8560                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8561
 8562                        if end_point == start_point {
 8563                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8564                                .saturating_sub(1);
 8565                            start_point =
 8566                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8567                        };
 8568
 8569                        (start_point..end_point, empty_str.clone())
 8570                    })
 8571                    .sorted_by_key(|(range, _)| range.start)
 8572                    .collect::<Vec<_>>();
 8573                buffer.update(cx, |this, cx| {
 8574                    this.edit(edits, None, cx);
 8575                })
 8576            }
 8577            this.refresh_inline_completion(true, false, window, cx);
 8578            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8579        });
 8580    }
 8581
 8582    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8583        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8584        self.transact(window, cx, |this, window, cx| {
 8585            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8586                s.move_with(|map, selection| {
 8587                    if selection.is_empty() {
 8588                        let cursor = movement::right(map, selection.head());
 8589                        selection.end = cursor;
 8590                        selection.reversed = true;
 8591                        selection.goal = SelectionGoal::None;
 8592                    }
 8593                })
 8594            });
 8595            this.insert("", window, cx);
 8596            this.refresh_inline_completion(true, false, window, cx);
 8597        });
 8598    }
 8599
 8600    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8601        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8602        if self.move_to_prev_snippet_tabstop(window, cx) {
 8603            return;
 8604        }
 8605        self.outdent(&Outdent, window, cx);
 8606    }
 8607
 8608    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8609        if self.move_to_next_snippet_tabstop(window, cx) {
 8610            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8611            return;
 8612        }
 8613        if self.read_only(cx) {
 8614            return;
 8615        }
 8616        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8617        let mut selections = self.selections.all_adjusted(cx);
 8618        let buffer = self.buffer.read(cx);
 8619        let snapshot = buffer.snapshot(cx);
 8620        let rows_iter = selections.iter().map(|s| s.head().row);
 8621        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8622
 8623        let mut edits = Vec::new();
 8624        let mut prev_edited_row = 0;
 8625        let mut row_delta = 0;
 8626        for selection in &mut selections {
 8627            if selection.start.row != prev_edited_row {
 8628                row_delta = 0;
 8629            }
 8630            prev_edited_row = selection.end.row;
 8631
 8632            // If the selection is non-empty, then increase the indentation of the selected lines.
 8633            if !selection.is_empty() {
 8634                row_delta =
 8635                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8636                continue;
 8637            }
 8638
 8639            // If the selection is empty and the cursor is in the leading whitespace before the
 8640            // suggested indentation, then auto-indent the line.
 8641            let cursor = selection.head();
 8642            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8643            if let Some(suggested_indent) =
 8644                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8645            {
 8646                if cursor.column < suggested_indent.len
 8647                    && cursor.column <= current_indent.len
 8648                    && current_indent.len <= suggested_indent.len
 8649                {
 8650                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8651                    selection.end = selection.start;
 8652                    if row_delta == 0 {
 8653                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8654                            cursor.row,
 8655                            current_indent,
 8656                            suggested_indent,
 8657                        ));
 8658                        row_delta = suggested_indent.len - current_indent.len;
 8659                    }
 8660                    continue;
 8661                }
 8662            }
 8663
 8664            // Otherwise, insert a hard or soft tab.
 8665            let settings = buffer.language_settings_at(cursor, cx);
 8666            let tab_size = if settings.hard_tabs {
 8667                IndentSize::tab()
 8668            } else {
 8669                let tab_size = settings.tab_size.get();
 8670                let indent_remainder = snapshot
 8671                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 8672                    .flat_map(str::chars)
 8673                    .fold(row_delta % tab_size, |counter: u32, c| {
 8674                        if c == '\t' {
 8675                            0
 8676                        } else {
 8677                            (counter + 1) % tab_size
 8678                        }
 8679                    });
 8680
 8681                let chars_to_next_tab_stop = tab_size - indent_remainder;
 8682                IndentSize::spaces(chars_to_next_tab_stop)
 8683            };
 8684            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 8685            selection.end = selection.start;
 8686            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 8687            row_delta += tab_size.len;
 8688        }
 8689
 8690        self.transact(window, cx, |this, window, cx| {
 8691            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8692            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8693                s.select(selections)
 8694            });
 8695            this.refresh_inline_completion(true, false, window, cx);
 8696        });
 8697    }
 8698
 8699    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 8700        if self.read_only(cx) {
 8701            return;
 8702        }
 8703        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8704        let mut selections = self.selections.all::<Point>(cx);
 8705        let mut prev_edited_row = 0;
 8706        let mut row_delta = 0;
 8707        let mut edits = Vec::new();
 8708        let buffer = self.buffer.read(cx);
 8709        let snapshot = buffer.snapshot(cx);
 8710        for selection in &mut selections {
 8711            if selection.start.row != prev_edited_row {
 8712                row_delta = 0;
 8713            }
 8714            prev_edited_row = selection.end.row;
 8715
 8716            row_delta =
 8717                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8718        }
 8719
 8720        self.transact(window, cx, |this, window, cx| {
 8721            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8722            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8723                s.select(selections)
 8724            });
 8725        });
 8726    }
 8727
 8728    fn indent_selection(
 8729        buffer: &MultiBuffer,
 8730        snapshot: &MultiBufferSnapshot,
 8731        selection: &mut Selection<Point>,
 8732        edits: &mut Vec<(Range<Point>, String)>,
 8733        delta_for_start_row: u32,
 8734        cx: &App,
 8735    ) -> u32 {
 8736        let settings = buffer.language_settings_at(selection.start, cx);
 8737        let tab_size = settings.tab_size.get();
 8738        let indent_kind = if settings.hard_tabs {
 8739            IndentKind::Tab
 8740        } else {
 8741            IndentKind::Space
 8742        };
 8743        let mut start_row = selection.start.row;
 8744        let mut end_row = selection.end.row + 1;
 8745
 8746        // If a selection ends at the beginning of a line, don't indent
 8747        // that last line.
 8748        if selection.end.column == 0 && selection.end.row > selection.start.row {
 8749            end_row -= 1;
 8750        }
 8751
 8752        // Avoid re-indenting a row that has already been indented by a
 8753        // previous selection, but still update this selection's column
 8754        // to reflect that indentation.
 8755        if delta_for_start_row > 0 {
 8756            start_row += 1;
 8757            selection.start.column += delta_for_start_row;
 8758            if selection.end.row == selection.start.row {
 8759                selection.end.column += delta_for_start_row;
 8760            }
 8761        }
 8762
 8763        let mut delta_for_end_row = 0;
 8764        let has_multiple_rows = start_row + 1 != end_row;
 8765        for row in start_row..end_row {
 8766            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 8767            let indent_delta = match (current_indent.kind, indent_kind) {
 8768                (IndentKind::Space, IndentKind::Space) => {
 8769                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 8770                    IndentSize::spaces(columns_to_next_tab_stop)
 8771                }
 8772                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 8773                (_, IndentKind::Tab) => IndentSize::tab(),
 8774            };
 8775
 8776            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 8777                0
 8778            } else {
 8779                selection.start.column
 8780            };
 8781            let row_start = Point::new(row, start);
 8782            edits.push((
 8783                row_start..row_start,
 8784                indent_delta.chars().collect::<String>(),
 8785            ));
 8786
 8787            // Update this selection's endpoints to reflect the indentation.
 8788            if row == selection.start.row {
 8789                selection.start.column += indent_delta.len;
 8790            }
 8791            if row == selection.end.row {
 8792                selection.end.column += indent_delta.len;
 8793                delta_for_end_row = indent_delta.len;
 8794            }
 8795        }
 8796
 8797        if selection.start.row == selection.end.row {
 8798            delta_for_start_row + delta_for_end_row
 8799        } else {
 8800            delta_for_end_row
 8801        }
 8802    }
 8803
 8804    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 8805        if self.read_only(cx) {
 8806            return;
 8807        }
 8808        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8810        let selections = self.selections.all::<Point>(cx);
 8811        let mut deletion_ranges = Vec::new();
 8812        let mut last_outdent = None;
 8813        {
 8814            let buffer = self.buffer.read(cx);
 8815            let snapshot = buffer.snapshot(cx);
 8816            for selection in &selections {
 8817                let settings = buffer.language_settings_at(selection.start, cx);
 8818                let tab_size = settings.tab_size.get();
 8819                let mut rows = selection.spanned_rows(false, &display_map);
 8820
 8821                // Avoid re-outdenting a row that has already been outdented by a
 8822                // previous selection.
 8823                if let Some(last_row) = last_outdent {
 8824                    if last_row == rows.start {
 8825                        rows.start = rows.start.next_row();
 8826                    }
 8827                }
 8828                let has_multiple_rows = rows.len() > 1;
 8829                for row in rows.iter_rows() {
 8830                    let indent_size = snapshot.indent_size_for_line(row);
 8831                    if indent_size.len > 0 {
 8832                        let deletion_len = match indent_size.kind {
 8833                            IndentKind::Space => {
 8834                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 8835                                if columns_to_prev_tab_stop == 0 {
 8836                                    tab_size
 8837                                } else {
 8838                                    columns_to_prev_tab_stop
 8839                                }
 8840                            }
 8841                            IndentKind::Tab => 1,
 8842                        };
 8843                        let start = if has_multiple_rows
 8844                            || deletion_len > selection.start.column
 8845                            || indent_size.len < selection.start.column
 8846                        {
 8847                            0
 8848                        } else {
 8849                            selection.start.column - deletion_len
 8850                        };
 8851                        deletion_ranges.push(
 8852                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 8853                        );
 8854                        last_outdent = Some(row);
 8855                    }
 8856                }
 8857            }
 8858        }
 8859
 8860        self.transact(window, cx, |this, window, cx| {
 8861            this.buffer.update(cx, |buffer, cx| {
 8862                let empty_str: Arc<str> = Arc::default();
 8863                buffer.edit(
 8864                    deletion_ranges
 8865                        .into_iter()
 8866                        .map(|range| (range, empty_str.clone())),
 8867                    None,
 8868                    cx,
 8869                );
 8870            });
 8871            let selections = this.selections.all::<usize>(cx);
 8872            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8873                s.select(selections)
 8874            });
 8875        });
 8876    }
 8877
 8878    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 8879        if self.read_only(cx) {
 8880            return;
 8881        }
 8882        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8883        let selections = self
 8884            .selections
 8885            .all::<usize>(cx)
 8886            .into_iter()
 8887            .map(|s| s.range());
 8888
 8889        self.transact(window, cx, |this, window, cx| {
 8890            this.buffer.update(cx, |buffer, cx| {
 8891                buffer.autoindent_ranges(selections, cx);
 8892            });
 8893            let selections = this.selections.all::<usize>(cx);
 8894            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8895                s.select(selections)
 8896            });
 8897        });
 8898    }
 8899
 8900    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 8901        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8902        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8903        let selections = self.selections.all::<Point>(cx);
 8904
 8905        let mut new_cursors = Vec::new();
 8906        let mut edit_ranges = Vec::new();
 8907        let mut selections = selections.iter().peekable();
 8908        while let Some(selection) = selections.next() {
 8909            let mut rows = selection.spanned_rows(false, &display_map);
 8910            let goal_display_column = selection.head().to_display_point(&display_map).column();
 8911
 8912            // Accumulate contiguous regions of rows that we want to delete.
 8913            while let Some(next_selection) = selections.peek() {
 8914                let next_rows = next_selection.spanned_rows(false, &display_map);
 8915                if next_rows.start <= rows.end {
 8916                    rows.end = next_rows.end;
 8917                    selections.next().unwrap();
 8918                } else {
 8919                    break;
 8920                }
 8921            }
 8922
 8923            let buffer = &display_map.buffer_snapshot;
 8924            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 8925            let edit_end;
 8926            let cursor_buffer_row;
 8927            if buffer.max_point().row >= rows.end.0 {
 8928                // If there's a line after the range, delete the \n from the end of the row range
 8929                // and position the cursor on the next line.
 8930                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 8931                cursor_buffer_row = rows.end;
 8932            } else {
 8933                // If there isn't a line after the range, delete the \n from the line before the
 8934                // start of the row range and position the cursor there.
 8935                edit_start = edit_start.saturating_sub(1);
 8936                edit_end = buffer.len();
 8937                cursor_buffer_row = rows.start.previous_row();
 8938            }
 8939
 8940            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 8941            *cursor.column_mut() =
 8942                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 8943
 8944            new_cursors.push((
 8945                selection.id,
 8946                buffer.anchor_after(cursor.to_point(&display_map)),
 8947            ));
 8948            edit_ranges.push(edit_start..edit_end);
 8949        }
 8950
 8951        self.transact(window, cx, |this, window, cx| {
 8952            let buffer = this.buffer.update(cx, |buffer, cx| {
 8953                let empty_str: Arc<str> = Arc::default();
 8954                buffer.edit(
 8955                    edit_ranges
 8956                        .into_iter()
 8957                        .map(|range| (range, empty_str.clone())),
 8958                    None,
 8959                    cx,
 8960                );
 8961                buffer.snapshot(cx)
 8962            });
 8963            let new_selections = new_cursors
 8964                .into_iter()
 8965                .map(|(id, cursor)| {
 8966                    let cursor = cursor.to_point(&buffer);
 8967                    Selection {
 8968                        id,
 8969                        start: cursor,
 8970                        end: cursor,
 8971                        reversed: false,
 8972                        goal: SelectionGoal::None,
 8973                    }
 8974                })
 8975                .collect();
 8976
 8977            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8978                s.select(new_selections);
 8979            });
 8980        });
 8981    }
 8982
 8983    pub fn join_lines_impl(
 8984        &mut self,
 8985        insert_whitespace: bool,
 8986        window: &mut Window,
 8987        cx: &mut Context<Self>,
 8988    ) {
 8989        if self.read_only(cx) {
 8990            return;
 8991        }
 8992        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 8993        for selection in self.selections.all::<Point>(cx) {
 8994            let start = MultiBufferRow(selection.start.row);
 8995            // Treat single line selections as if they include the next line. Otherwise this action
 8996            // would do nothing for single line selections individual cursors.
 8997            let end = if selection.start.row == selection.end.row {
 8998                MultiBufferRow(selection.start.row + 1)
 8999            } else {
 9000                MultiBufferRow(selection.end.row)
 9001            };
 9002
 9003            if let Some(last_row_range) = row_ranges.last_mut() {
 9004                if start <= last_row_range.end {
 9005                    last_row_range.end = end;
 9006                    continue;
 9007                }
 9008            }
 9009            row_ranges.push(start..end);
 9010        }
 9011
 9012        let snapshot = self.buffer.read(cx).snapshot(cx);
 9013        let mut cursor_positions = Vec::new();
 9014        for row_range in &row_ranges {
 9015            let anchor = snapshot.anchor_before(Point::new(
 9016                row_range.end.previous_row().0,
 9017                snapshot.line_len(row_range.end.previous_row()),
 9018            ));
 9019            cursor_positions.push(anchor..anchor);
 9020        }
 9021
 9022        self.transact(window, cx, |this, window, cx| {
 9023            for row_range in row_ranges.into_iter().rev() {
 9024                for row in row_range.iter_rows().rev() {
 9025                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9026                    let next_line_row = row.next_row();
 9027                    let indent = snapshot.indent_size_for_line(next_line_row);
 9028                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9029
 9030                    let replace =
 9031                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9032                            " "
 9033                        } else {
 9034                            ""
 9035                        };
 9036
 9037                    this.buffer.update(cx, |buffer, cx| {
 9038                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9039                    });
 9040                }
 9041            }
 9042
 9043            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9044                s.select_anchor_ranges(cursor_positions)
 9045            });
 9046        });
 9047    }
 9048
 9049    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9050        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9051        self.join_lines_impl(true, window, cx);
 9052    }
 9053
 9054    pub fn sort_lines_case_sensitive(
 9055        &mut self,
 9056        _: &SortLinesCaseSensitive,
 9057        window: &mut Window,
 9058        cx: &mut Context<Self>,
 9059    ) {
 9060        self.manipulate_lines(window, cx, |lines| lines.sort())
 9061    }
 9062
 9063    pub fn sort_lines_case_insensitive(
 9064        &mut self,
 9065        _: &SortLinesCaseInsensitive,
 9066        window: &mut Window,
 9067        cx: &mut Context<Self>,
 9068    ) {
 9069        self.manipulate_lines(window, cx, |lines| {
 9070            lines.sort_by_key(|line| line.to_lowercase())
 9071        })
 9072    }
 9073
 9074    pub fn unique_lines_case_insensitive(
 9075        &mut self,
 9076        _: &UniqueLinesCaseInsensitive,
 9077        window: &mut Window,
 9078        cx: &mut Context<Self>,
 9079    ) {
 9080        self.manipulate_lines(window, cx, |lines| {
 9081            let mut seen = HashSet::default();
 9082            lines.retain(|line| seen.insert(line.to_lowercase()));
 9083        })
 9084    }
 9085
 9086    pub fn unique_lines_case_sensitive(
 9087        &mut self,
 9088        _: &UniqueLinesCaseSensitive,
 9089        window: &mut Window,
 9090        cx: &mut Context<Self>,
 9091    ) {
 9092        self.manipulate_lines(window, cx, |lines| {
 9093            let mut seen = HashSet::default();
 9094            lines.retain(|line| seen.insert(*line));
 9095        })
 9096    }
 9097
 9098    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9099        let Some(project) = self.project.clone() else {
 9100            return;
 9101        };
 9102        self.reload(project, window, cx)
 9103            .detach_and_notify_err(window, cx);
 9104    }
 9105
 9106    pub fn restore_file(
 9107        &mut self,
 9108        _: &::git::RestoreFile,
 9109        window: &mut Window,
 9110        cx: &mut Context<Self>,
 9111    ) {
 9112        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9113        let mut buffer_ids = HashSet::default();
 9114        let snapshot = self.buffer().read(cx).snapshot(cx);
 9115        for selection in self.selections.all::<usize>(cx) {
 9116            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9117        }
 9118
 9119        let buffer = self.buffer().read(cx);
 9120        let ranges = buffer_ids
 9121            .into_iter()
 9122            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9123            .collect::<Vec<_>>();
 9124
 9125        self.restore_hunks_in_ranges(ranges, window, cx);
 9126    }
 9127
 9128    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9129        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9130        let selections = self
 9131            .selections
 9132            .all(cx)
 9133            .into_iter()
 9134            .map(|s| s.range())
 9135            .collect();
 9136        self.restore_hunks_in_ranges(selections, window, cx);
 9137    }
 9138
 9139    pub fn restore_hunks_in_ranges(
 9140        &mut self,
 9141        ranges: Vec<Range<Point>>,
 9142        window: &mut Window,
 9143        cx: &mut Context<Editor>,
 9144    ) {
 9145        let mut revert_changes = HashMap::default();
 9146        let chunk_by = self
 9147            .snapshot(window, cx)
 9148            .hunks_for_ranges(ranges)
 9149            .into_iter()
 9150            .chunk_by(|hunk| hunk.buffer_id);
 9151        for (buffer_id, hunks) in &chunk_by {
 9152            let hunks = hunks.collect::<Vec<_>>();
 9153            for hunk in &hunks {
 9154                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9155            }
 9156            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9157        }
 9158        drop(chunk_by);
 9159        if !revert_changes.is_empty() {
 9160            self.transact(window, cx, |editor, window, cx| {
 9161                editor.restore(revert_changes, window, cx);
 9162            });
 9163        }
 9164    }
 9165
 9166    pub fn open_active_item_in_terminal(
 9167        &mut self,
 9168        _: &OpenInTerminal,
 9169        window: &mut Window,
 9170        cx: &mut Context<Self>,
 9171    ) {
 9172        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9173            let project_path = buffer.read(cx).project_path(cx)?;
 9174            let project = self.project.as_ref()?.read(cx);
 9175            let entry = project.entry_for_path(&project_path, cx)?;
 9176            let parent = match &entry.canonical_path {
 9177                Some(canonical_path) => canonical_path.to_path_buf(),
 9178                None => project.absolute_path(&project_path, cx)?,
 9179            }
 9180            .parent()?
 9181            .to_path_buf();
 9182            Some(parent)
 9183        }) {
 9184            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9185        }
 9186    }
 9187
 9188    fn set_breakpoint_context_menu(
 9189        &mut self,
 9190        display_row: DisplayRow,
 9191        position: Option<Anchor>,
 9192        clicked_point: gpui::Point<Pixels>,
 9193        window: &mut Window,
 9194        cx: &mut Context<Self>,
 9195    ) {
 9196        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9197            return;
 9198        }
 9199        let source = self
 9200            .buffer
 9201            .read(cx)
 9202            .snapshot(cx)
 9203            .anchor_before(Point::new(display_row.0, 0u32));
 9204
 9205        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9206
 9207        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9208            self,
 9209            source,
 9210            clicked_point,
 9211            context_menu,
 9212            window,
 9213            cx,
 9214        );
 9215    }
 9216
 9217    fn add_edit_breakpoint_block(
 9218        &mut self,
 9219        anchor: Anchor,
 9220        breakpoint: &Breakpoint,
 9221        edit_action: BreakpointPromptEditAction,
 9222        window: &mut Window,
 9223        cx: &mut Context<Self>,
 9224    ) {
 9225        let weak_editor = cx.weak_entity();
 9226        let bp_prompt = cx.new(|cx| {
 9227            BreakpointPromptEditor::new(
 9228                weak_editor,
 9229                anchor,
 9230                breakpoint.clone(),
 9231                edit_action,
 9232                window,
 9233                cx,
 9234            )
 9235        });
 9236
 9237        let height = bp_prompt.update(cx, |this, cx| {
 9238            this.prompt
 9239                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9240        });
 9241        let cloned_prompt = bp_prompt.clone();
 9242        let blocks = vec![BlockProperties {
 9243            style: BlockStyle::Sticky,
 9244            placement: BlockPlacement::Above(anchor),
 9245            height: Some(height),
 9246            render: Arc::new(move |cx| {
 9247                *cloned_prompt.read(cx).gutter_dimensions.lock() = *cx.gutter_dimensions;
 9248                cloned_prompt.clone().into_any_element()
 9249            }),
 9250            priority: 0,
 9251        }];
 9252
 9253        let focus_handle = bp_prompt.focus_handle(cx);
 9254        window.focus(&focus_handle);
 9255
 9256        let block_ids = self.insert_blocks(blocks, None, cx);
 9257        bp_prompt.update(cx, |prompt, _| {
 9258            prompt.add_block_ids(block_ids);
 9259        });
 9260    }
 9261
 9262    pub(crate) fn breakpoint_at_row(
 9263        &self,
 9264        row: u32,
 9265        window: &mut Window,
 9266        cx: &mut Context<Self>,
 9267    ) -> Option<(Anchor, Breakpoint)> {
 9268        let snapshot = self.snapshot(window, cx);
 9269        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9270
 9271        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9272    }
 9273
 9274    pub(crate) fn breakpoint_at_anchor(
 9275        &self,
 9276        breakpoint_position: Anchor,
 9277        snapshot: &EditorSnapshot,
 9278        cx: &mut Context<Self>,
 9279    ) -> Option<(Anchor, Breakpoint)> {
 9280        let project = self.project.clone()?;
 9281
 9282        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9283            snapshot
 9284                .buffer_snapshot
 9285                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9286        })?;
 9287
 9288        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9289        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9290        let buffer_snapshot = buffer.read(cx).snapshot();
 9291
 9292        let row = buffer_snapshot
 9293            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9294            .row;
 9295
 9296        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9297        let anchor_end = snapshot
 9298            .buffer_snapshot
 9299            .anchor_after(Point::new(row, line_len));
 9300
 9301        let bp = self
 9302            .breakpoint_store
 9303            .as_ref()?
 9304            .read_with(cx, |breakpoint_store, cx| {
 9305                breakpoint_store
 9306                    .breakpoints(
 9307                        &buffer,
 9308                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9309                        &buffer_snapshot,
 9310                        cx,
 9311                    )
 9312                    .next()
 9313                    .and_then(|(anchor, bp)| {
 9314                        let breakpoint_row = buffer_snapshot
 9315                            .summary_for_anchor::<text::PointUtf16>(anchor)
 9316                            .row;
 9317
 9318                        if breakpoint_row == row {
 9319                            snapshot
 9320                                .buffer_snapshot
 9321                                .anchor_in_excerpt(enclosing_excerpt, *anchor)
 9322                                .map(|anchor| (anchor, bp.clone()))
 9323                        } else {
 9324                            None
 9325                        }
 9326                    })
 9327            });
 9328        bp
 9329    }
 9330
 9331    pub fn edit_log_breakpoint(
 9332        &mut self,
 9333        _: &EditLogBreakpoint,
 9334        window: &mut Window,
 9335        cx: &mut Context<Self>,
 9336    ) {
 9337        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9338            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9339                message: None,
 9340                state: BreakpointState::Enabled,
 9341                condition: None,
 9342                hit_condition: None,
 9343            });
 9344
 9345            self.add_edit_breakpoint_block(
 9346                anchor,
 9347                &breakpoint,
 9348                BreakpointPromptEditAction::Log,
 9349                window,
 9350                cx,
 9351            );
 9352        }
 9353    }
 9354
 9355    fn breakpoints_at_cursors(
 9356        &self,
 9357        window: &mut Window,
 9358        cx: &mut Context<Self>,
 9359    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9360        let snapshot = self.snapshot(window, cx);
 9361        let cursors = self
 9362            .selections
 9363            .disjoint_anchors()
 9364            .into_iter()
 9365            .map(|selection| {
 9366                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9367
 9368                let breakpoint_position = self
 9369                    .breakpoint_at_row(cursor_position.row, window, cx)
 9370                    .map(|bp| bp.0)
 9371                    .unwrap_or_else(|| {
 9372                        snapshot
 9373                            .display_snapshot
 9374                            .buffer_snapshot
 9375                            .anchor_after(Point::new(cursor_position.row, 0))
 9376                    });
 9377
 9378                let breakpoint = self
 9379                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9380                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9381
 9382                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9383            })
 9384            // 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.
 9385            .collect::<HashMap<Anchor, _>>();
 9386
 9387        cursors.into_iter().collect()
 9388    }
 9389
 9390    pub fn enable_breakpoint(
 9391        &mut self,
 9392        _: &crate::actions::EnableBreakpoint,
 9393        window: &mut Window,
 9394        cx: &mut Context<Self>,
 9395    ) {
 9396        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9397            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9398                continue;
 9399            };
 9400            self.edit_breakpoint_at_anchor(
 9401                anchor,
 9402                breakpoint,
 9403                BreakpointEditAction::InvertState,
 9404                cx,
 9405            );
 9406        }
 9407    }
 9408
 9409    pub fn disable_breakpoint(
 9410        &mut self,
 9411        _: &crate::actions::DisableBreakpoint,
 9412        window: &mut Window,
 9413        cx: &mut Context<Self>,
 9414    ) {
 9415        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9416            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9417                continue;
 9418            };
 9419            self.edit_breakpoint_at_anchor(
 9420                anchor,
 9421                breakpoint,
 9422                BreakpointEditAction::InvertState,
 9423                cx,
 9424            );
 9425        }
 9426    }
 9427
 9428    pub fn toggle_breakpoint(
 9429        &mut self,
 9430        _: &crate::actions::ToggleBreakpoint,
 9431        window: &mut Window,
 9432        cx: &mut Context<Self>,
 9433    ) {
 9434        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9435            if let Some(breakpoint) = breakpoint {
 9436                self.edit_breakpoint_at_anchor(
 9437                    anchor,
 9438                    breakpoint,
 9439                    BreakpointEditAction::Toggle,
 9440                    cx,
 9441                );
 9442            } else {
 9443                self.edit_breakpoint_at_anchor(
 9444                    anchor,
 9445                    Breakpoint::new_standard(),
 9446                    BreakpointEditAction::Toggle,
 9447                    cx,
 9448                );
 9449            }
 9450        }
 9451    }
 9452
 9453    pub fn edit_breakpoint_at_anchor(
 9454        &mut self,
 9455        breakpoint_position: Anchor,
 9456        breakpoint: Breakpoint,
 9457        edit_action: BreakpointEditAction,
 9458        cx: &mut Context<Self>,
 9459    ) {
 9460        let Some(breakpoint_store) = &self.breakpoint_store else {
 9461            return;
 9462        };
 9463
 9464        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9465            if breakpoint_position == Anchor::min() {
 9466                self.buffer()
 9467                    .read(cx)
 9468                    .excerpt_buffer_ids()
 9469                    .into_iter()
 9470                    .next()
 9471            } else {
 9472                None
 9473            }
 9474        }) else {
 9475            return;
 9476        };
 9477
 9478        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9479            return;
 9480        };
 9481
 9482        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9483            breakpoint_store.toggle_breakpoint(
 9484                buffer,
 9485                (breakpoint_position.text_anchor, breakpoint),
 9486                edit_action,
 9487                cx,
 9488            );
 9489        });
 9490
 9491        cx.notify();
 9492    }
 9493
 9494    #[cfg(any(test, feature = "test-support"))]
 9495    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9496        self.breakpoint_store.clone()
 9497    }
 9498
 9499    pub fn prepare_restore_change(
 9500        &self,
 9501        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9502        hunk: &MultiBufferDiffHunk,
 9503        cx: &mut App,
 9504    ) -> Option<()> {
 9505        if hunk.is_created_file() {
 9506            return None;
 9507        }
 9508        let buffer = self.buffer.read(cx);
 9509        let diff = buffer.diff_for(hunk.buffer_id)?;
 9510        let buffer = buffer.buffer(hunk.buffer_id)?;
 9511        let buffer = buffer.read(cx);
 9512        let original_text = diff
 9513            .read(cx)
 9514            .base_text()
 9515            .as_rope()
 9516            .slice(hunk.diff_base_byte_range.clone());
 9517        let buffer_snapshot = buffer.snapshot();
 9518        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9519        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9520            probe
 9521                .0
 9522                .start
 9523                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9524                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9525        }) {
 9526            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9527            Some(())
 9528        } else {
 9529            None
 9530        }
 9531    }
 9532
 9533    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9534        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9535    }
 9536
 9537    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9538        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9539    }
 9540
 9541    fn manipulate_lines<Fn>(
 9542        &mut self,
 9543        window: &mut Window,
 9544        cx: &mut Context<Self>,
 9545        mut callback: Fn,
 9546    ) where
 9547        Fn: FnMut(&mut Vec<&str>),
 9548    {
 9549        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9550
 9551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9552        let buffer = self.buffer.read(cx).snapshot(cx);
 9553
 9554        let mut edits = Vec::new();
 9555
 9556        let selections = self.selections.all::<Point>(cx);
 9557        let mut selections = selections.iter().peekable();
 9558        let mut contiguous_row_selections = Vec::new();
 9559        let mut new_selections = Vec::new();
 9560        let mut added_lines = 0;
 9561        let mut removed_lines = 0;
 9562
 9563        while let Some(selection) = selections.next() {
 9564            let (start_row, end_row) = consume_contiguous_rows(
 9565                &mut contiguous_row_selections,
 9566                selection,
 9567                &display_map,
 9568                &mut selections,
 9569            );
 9570
 9571            let start_point = Point::new(start_row.0, 0);
 9572            let end_point = Point::new(
 9573                end_row.previous_row().0,
 9574                buffer.line_len(end_row.previous_row()),
 9575            );
 9576            let text = buffer
 9577                .text_for_range(start_point..end_point)
 9578                .collect::<String>();
 9579
 9580            let mut lines = text.split('\n').collect_vec();
 9581
 9582            let lines_before = lines.len();
 9583            callback(&mut lines);
 9584            let lines_after = lines.len();
 9585
 9586            edits.push((start_point..end_point, lines.join("\n")));
 9587
 9588            // Selections must change based on added and removed line count
 9589            let start_row =
 9590                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9591            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9592            new_selections.push(Selection {
 9593                id: selection.id,
 9594                start: start_row,
 9595                end: end_row,
 9596                goal: SelectionGoal::None,
 9597                reversed: selection.reversed,
 9598            });
 9599
 9600            if lines_after > lines_before {
 9601                added_lines += lines_after - lines_before;
 9602            } else if lines_before > lines_after {
 9603                removed_lines += lines_before - lines_after;
 9604            }
 9605        }
 9606
 9607        self.transact(window, cx, |this, window, cx| {
 9608            let buffer = this.buffer.update(cx, |buffer, cx| {
 9609                buffer.edit(edits, None, cx);
 9610                buffer.snapshot(cx)
 9611            });
 9612
 9613            // Recalculate offsets on newly edited buffer
 9614            let new_selections = new_selections
 9615                .iter()
 9616                .map(|s| {
 9617                    let start_point = Point::new(s.start.0, 0);
 9618                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9619                    Selection {
 9620                        id: s.id,
 9621                        start: buffer.point_to_offset(start_point),
 9622                        end: buffer.point_to_offset(end_point),
 9623                        goal: s.goal,
 9624                        reversed: s.reversed,
 9625                    }
 9626                })
 9627                .collect();
 9628
 9629            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9630                s.select(new_selections);
 9631            });
 9632
 9633            this.request_autoscroll(Autoscroll::fit(), cx);
 9634        });
 9635    }
 9636
 9637    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9638        self.manipulate_text(window, cx, |text| {
 9639            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9640            if has_upper_case_characters {
 9641                text.to_lowercase()
 9642            } else {
 9643                text.to_uppercase()
 9644            }
 9645        })
 9646    }
 9647
 9648    pub fn convert_to_upper_case(
 9649        &mut self,
 9650        _: &ConvertToUpperCase,
 9651        window: &mut Window,
 9652        cx: &mut Context<Self>,
 9653    ) {
 9654        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9655    }
 9656
 9657    pub fn convert_to_lower_case(
 9658        &mut self,
 9659        _: &ConvertToLowerCase,
 9660        window: &mut Window,
 9661        cx: &mut Context<Self>,
 9662    ) {
 9663        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9664    }
 9665
 9666    pub fn convert_to_title_case(
 9667        &mut self,
 9668        _: &ConvertToTitleCase,
 9669        window: &mut Window,
 9670        cx: &mut Context<Self>,
 9671    ) {
 9672        self.manipulate_text(window, cx, |text| {
 9673            text.split('\n')
 9674                .map(|line| line.to_case(Case::Title))
 9675                .join("\n")
 9676        })
 9677    }
 9678
 9679    pub fn convert_to_snake_case(
 9680        &mut self,
 9681        _: &ConvertToSnakeCase,
 9682        window: &mut Window,
 9683        cx: &mut Context<Self>,
 9684    ) {
 9685        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
 9686    }
 9687
 9688    pub fn convert_to_kebab_case(
 9689        &mut self,
 9690        _: &ConvertToKebabCase,
 9691        window: &mut Window,
 9692        cx: &mut Context<Self>,
 9693    ) {
 9694        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
 9695    }
 9696
 9697    pub fn convert_to_upper_camel_case(
 9698        &mut self,
 9699        _: &ConvertToUpperCamelCase,
 9700        window: &mut Window,
 9701        cx: &mut Context<Self>,
 9702    ) {
 9703        self.manipulate_text(window, cx, |text| {
 9704            text.split('\n')
 9705                .map(|line| line.to_case(Case::UpperCamel))
 9706                .join("\n")
 9707        })
 9708    }
 9709
 9710    pub fn convert_to_lower_camel_case(
 9711        &mut self,
 9712        _: &ConvertToLowerCamelCase,
 9713        window: &mut Window,
 9714        cx: &mut Context<Self>,
 9715    ) {
 9716        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
 9717    }
 9718
 9719    pub fn convert_to_opposite_case(
 9720        &mut self,
 9721        _: &ConvertToOppositeCase,
 9722        window: &mut Window,
 9723        cx: &mut Context<Self>,
 9724    ) {
 9725        self.manipulate_text(window, cx, |text| {
 9726            text.chars()
 9727                .fold(String::with_capacity(text.len()), |mut t, c| {
 9728                    if c.is_uppercase() {
 9729                        t.extend(c.to_lowercase());
 9730                    } else {
 9731                        t.extend(c.to_uppercase());
 9732                    }
 9733                    t
 9734                })
 9735        })
 9736    }
 9737
 9738    pub fn convert_to_rot13(
 9739        &mut self,
 9740        _: &ConvertToRot13,
 9741        window: &mut Window,
 9742        cx: &mut Context<Self>,
 9743    ) {
 9744        self.manipulate_text(window, cx, |text| {
 9745            text.chars()
 9746                .map(|c| match c {
 9747                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
 9748                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
 9749                    _ => c,
 9750                })
 9751                .collect()
 9752        })
 9753    }
 9754
 9755    pub fn convert_to_rot47(
 9756        &mut self,
 9757        _: &ConvertToRot47,
 9758        window: &mut Window,
 9759        cx: &mut Context<Self>,
 9760    ) {
 9761        self.manipulate_text(window, cx, |text| {
 9762            text.chars()
 9763                .map(|c| {
 9764                    let code_point = c as u32;
 9765                    if code_point >= 33 && code_point <= 126 {
 9766                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
 9767                    }
 9768                    c
 9769                })
 9770                .collect()
 9771        })
 9772    }
 9773
 9774    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
 9775    where
 9776        Fn: FnMut(&str) -> String,
 9777    {
 9778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9779        let buffer = self.buffer.read(cx).snapshot(cx);
 9780
 9781        let mut new_selections = Vec::new();
 9782        let mut edits = Vec::new();
 9783        let mut selection_adjustment = 0i32;
 9784
 9785        for selection in self.selections.all::<usize>(cx) {
 9786            let selection_is_empty = selection.is_empty();
 9787
 9788            let (start, end) = if selection_is_empty {
 9789                let word_range = movement::surrounding_word(
 9790                    &display_map,
 9791                    selection.start.to_display_point(&display_map),
 9792                );
 9793                let start = word_range.start.to_offset(&display_map, Bias::Left);
 9794                let end = word_range.end.to_offset(&display_map, Bias::Left);
 9795                (start, end)
 9796            } else {
 9797                (selection.start, selection.end)
 9798            };
 9799
 9800            let text = buffer.text_for_range(start..end).collect::<String>();
 9801            let old_length = text.len() as i32;
 9802            let text = callback(&text);
 9803
 9804            new_selections.push(Selection {
 9805                start: (start as i32 - selection_adjustment) as usize,
 9806                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 9807                goal: SelectionGoal::None,
 9808                ..selection
 9809            });
 9810
 9811            selection_adjustment += old_length - text.len() as i32;
 9812
 9813            edits.push((start..end, text));
 9814        }
 9815
 9816        self.transact(window, cx, |this, window, cx| {
 9817            this.buffer.update(cx, |buffer, cx| {
 9818                buffer.edit(edits, None, cx);
 9819            });
 9820
 9821            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9822                s.select(new_selections);
 9823            });
 9824
 9825            this.request_autoscroll(Autoscroll::fit(), cx);
 9826        });
 9827    }
 9828
 9829    pub fn duplicate(
 9830        &mut self,
 9831        upwards: bool,
 9832        whole_lines: bool,
 9833        window: &mut Window,
 9834        cx: &mut Context<Self>,
 9835    ) {
 9836        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9837
 9838        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9839        let buffer = &display_map.buffer_snapshot;
 9840        let selections = self.selections.all::<Point>(cx);
 9841
 9842        let mut edits = Vec::new();
 9843        let mut selections_iter = selections.iter().peekable();
 9844        while let Some(selection) = selections_iter.next() {
 9845            let mut rows = selection.spanned_rows(false, &display_map);
 9846            // duplicate line-wise
 9847            if whole_lines || selection.start == selection.end {
 9848                // Avoid duplicating the same lines twice.
 9849                while let Some(next_selection) = selections_iter.peek() {
 9850                    let next_rows = next_selection.spanned_rows(false, &display_map);
 9851                    if next_rows.start < rows.end {
 9852                        rows.end = next_rows.end;
 9853                        selections_iter.next().unwrap();
 9854                    } else {
 9855                        break;
 9856                    }
 9857                }
 9858
 9859                // Copy the text from the selected row region and splice it either at the start
 9860                // or end of the region.
 9861                let start = Point::new(rows.start.0, 0);
 9862                let end = Point::new(
 9863                    rows.end.previous_row().0,
 9864                    buffer.line_len(rows.end.previous_row()),
 9865                );
 9866                let text = buffer
 9867                    .text_for_range(start..end)
 9868                    .chain(Some("\n"))
 9869                    .collect::<String>();
 9870                let insert_location = if upwards {
 9871                    Point::new(rows.end.0, 0)
 9872                } else {
 9873                    start
 9874                };
 9875                edits.push((insert_location..insert_location, text));
 9876            } else {
 9877                // duplicate character-wise
 9878                let start = selection.start;
 9879                let end = selection.end;
 9880                let text = buffer.text_for_range(start..end).collect::<String>();
 9881                edits.push((selection.end..selection.end, text));
 9882            }
 9883        }
 9884
 9885        self.transact(window, cx, |this, _, cx| {
 9886            this.buffer.update(cx, |buffer, cx| {
 9887                buffer.edit(edits, None, cx);
 9888            });
 9889
 9890            this.request_autoscroll(Autoscroll::fit(), cx);
 9891        });
 9892    }
 9893
 9894    pub fn duplicate_line_up(
 9895        &mut self,
 9896        _: &DuplicateLineUp,
 9897        window: &mut Window,
 9898        cx: &mut Context<Self>,
 9899    ) {
 9900        self.duplicate(true, true, window, cx);
 9901    }
 9902
 9903    pub fn duplicate_line_down(
 9904        &mut self,
 9905        _: &DuplicateLineDown,
 9906        window: &mut Window,
 9907        cx: &mut Context<Self>,
 9908    ) {
 9909        self.duplicate(false, true, window, cx);
 9910    }
 9911
 9912    pub fn duplicate_selection(
 9913        &mut self,
 9914        _: &DuplicateSelection,
 9915        window: &mut Window,
 9916        cx: &mut Context<Self>,
 9917    ) {
 9918        self.duplicate(false, false, window, cx);
 9919    }
 9920
 9921    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
 9922        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9923
 9924        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9925        let buffer = self.buffer.read(cx).snapshot(cx);
 9926
 9927        let mut edits = Vec::new();
 9928        let mut unfold_ranges = Vec::new();
 9929        let mut refold_creases = Vec::new();
 9930
 9931        let selections = self.selections.all::<Point>(cx);
 9932        let mut selections = selections.iter().peekable();
 9933        let mut contiguous_row_selections = Vec::new();
 9934        let mut new_selections = Vec::new();
 9935
 9936        while let Some(selection) = selections.next() {
 9937            // Find all the selections that span a contiguous row range
 9938            let (start_row, end_row) = consume_contiguous_rows(
 9939                &mut contiguous_row_selections,
 9940                selection,
 9941                &display_map,
 9942                &mut selections,
 9943            );
 9944
 9945            // Move the text spanned by the row range to be before the line preceding the row range
 9946            if start_row.0 > 0 {
 9947                let range_to_move = Point::new(
 9948                    start_row.previous_row().0,
 9949                    buffer.line_len(start_row.previous_row()),
 9950                )
 9951                    ..Point::new(
 9952                        end_row.previous_row().0,
 9953                        buffer.line_len(end_row.previous_row()),
 9954                    );
 9955                let insertion_point = display_map
 9956                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 9957                    .0;
 9958
 9959                // Don't move lines across excerpts
 9960                if buffer
 9961                    .excerpt_containing(insertion_point..range_to_move.end)
 9962                    .is_some()
 9963                {
 9964                    let text = buffer
 9965                        .text_for_range(range_to_move.clone())
 9966                        .flat_map(|s| s.chars())
 9967                        .skip(1)
 9968                        .chain(['\n'])
 9969                        .collect::<String>();
 9970
 9971                    edits.push((
 9972                        buffer.anchor_after(range_to_move.start)
 9973                            ..buffer.anchor_before(range_to_move.end),
 9974                        String::new(),
 9975                    ));
 9976                    let insertion_anchor = buffer.anchor_after(insertion_point);
 9977                    edits.push((insertion_anchor..insertion_anchor, text));
 9978
 9979                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 9980
 9981                    // Move selections up
 9982                    new_selections.extend(contiguous_row_selections.drain(..).map(
 9983                        |mut selection| {
 9984                            selection.start.row -= row_delta;
 9985                            selection.end.row -= row_delta;
 9986                            selection
 9987                        },
 9988                    ));
 9989
 9990                    // Move folds up
 9991                    unfold_ranges.push(range_to_move.clone());
 9992                    for fold in display_map.folds_in_range(
 9993                        buffer.anchor_before(range_to_move.start)
 9994                            ..buffer.anchor_after(range_to_move.end),
 9995                    ) {
 9996                        let mut start = fold.range.start.to_point(&buffer);
 9997                        let mut end = fold.range.end.to_point(&buffer);
 9998                        start.row -= row_delta;
 9999                        end.row -= row_delta;
10000                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10001                    }
10002                }
10003            }
10004
10005            // If we didn't move line(s), preserve the existing selections
10006            new_selections.append(&mut contiguous_row_selections);
10007        }
10008
10009        self.transact(window, cx, |this, window, cx| {
10010            this.unfold_ranges(&unfold_ranges, true, true, cx);
10011            this.buffer.update(cx, |buffer, cx| {
10012                for (range, text) in edits {
10013                    buffer.edit([(range, text)], None, cx);
10014                }
10015            });
10016            this.fold_creases(refold_creases, true, window, cx);
10017            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10018                s.select(new_selections);
10019            })
10020        });
10021    }
10022
10023    pub fn move_line_down(
10024        &mut self,
10025        _: &MoveLineDown,
10026        window: &mut Window,
10027        cx: &mut Context<Self>,
10028    ) {
10029        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10030
10031        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10032        let buffer = self.buffer.read(cx).snapshot(cx);
10033
10034        let mut edits = Vec::new();
10035        let mut unfold_ranges = Vec::new();
10036        let mut refold_creases = Vec::new();
10037
10038        let selections = self.selections.all::<Point>(cx);
10039        let mut selections = selections.iter().peekable();
10040        let mut contiguous_row_selections = Vec::new();
10041        let mut new_selections = Vec::new();
10042
10043        while let Some(selection) = selections.next() {
10044            // Find all the selections that span a contiguous row range
10045            let (start_row, end_row) = consume_contiguous_rows(
10046                &mut contiguous_row_selections,
10047                selection,
10048                &display_map,
10049                &mut selections,
10050            );
10051
10052            // Move the text spanned by the row range to be after the last line of the row range
10053            if end_row.0 <= buffer.max_point().row {
10054                let range_to_move =
10055                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10056                let insertion_point = display_map
10057                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10058                    .0;
10059
10060                // Don't move lines across excerpt boundaries
10061                if buffer
10062                    .excerpt_containing(range_to_move.start..insertion_point)
10063                    .is_some()
10064                {
10065                    let mut text = String::from("\n");
10066                    text.extend(buffer.text_for_range(range_to_move.clone()));
10067                    text.pop(); // Drop trailing newline
10068                    edits.push((
10069                        buffer.anchor_after(range_to_move.start)
10070                            ..buffer.anchor_before(range_to_move.end),
10071                        String::new(),
10072                    ));
10073                    let insertion_anchor = buffer.anchor_after(insertion_point);
10074                    edits.push((insertion_anchor..insertion_anchor, text));
10075
10076                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10077
10078                    // Move selections down
10079                    new_selections.extend(contiguous_row_selections.drain(..).map(
10080                        |mut selection| {
10081                            selection.start.row += row_delta;
10082                            selection.end.row += row_delta;
10083                            selection
10084                        },
10085                    ));
10086
10087                    // Move folds down
10088                    unfold_ranges.push(range_to_move.clone());
10089                    for fold in display_map.folds_in_range(
10090                        buffer.anchor_before(range_to_move.start)
10091                            ..buffer.anchor_after(range_to_move.end),
10092                    ) {
10093                        let mut start = fold.range.start.to_point(&buffer);
10094                        let mut end = fold.range.end.to_point(&buffer);
10095                        start.row += row_delta;
10096                        end.row += row_delta;
10097                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10098                    }
10099                }
10100            }
10101
10102            // If we didn't move line(s), preserve the existing selections
10103            new_selections.append(&mut contiguous_row_selections);
10104        }
10105
10106        self.transact(window, cx, |this, window, cx| {
10107            this.unfold_ranges(&unfold_ranges, true, true, cx);
10108            this.buffer.update(cx, |buffer, cx| {
10109                for (range, text) in edits {
10110                    buffer.edit([(range, text)], None, cx);
10111                }
10112            });
10113            this.fold_creases(refold_creases, true, window, cx);
10114            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10115                s.select(new_selections)
10116            });
10117        });
10118    }
10119
10120    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10121        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10122        let text_layout_details = &self.text_layout_details(window);
10123        self.transact(window, cx, |this, window, cx| {
10124            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10125                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10126                s.move_with(|display_map, selection| {
10127                    if !selection.is_empty() {
10128                        return;
10129                    }
10130
10131                    let mut head = selection.head();
10132                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10133                    if head.column() == display_map.line_len(head.row()) {
10134                        transpose_offset = display_map
10135                            .buffer_snapshot
10136                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10137                    }
10138
10139                    if transpose_offset == 0 {
10140                        return;
10141                    }
10142
10143                    *head.column_mut() += 1;
10144                    head = display_map.clip_point(head, Bias::Right);
10145                    let goal = SelectionGoal::HorizontalPosition(
10146                        display_map
10147                            .x_for_display_point(head, text_layout_details)
10148                            .into(),
10149                    );
10150                    selection.collapse_to(head, goal);
10151
10152                    let transpose_start = display_map
10153                        .buffer_snapshot
10154                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10155                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10156                        let transpose_end = display_map
10157                            .buffer_snapshot
10158                            .clip_offset(transpose_offset + 1, Bias::Right);
10159                        if let Some(ch) =
10160                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10161                        {
10162                            edits.push((transpose_start..transpose_offset, String::new()));
10163                            edits.push((transpose_end..transpose_end, ch.to_string()));
10164                        }
10165                    }
10166                });
10167                edits
10168            });
10169            this.buffer
10170                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10171            let selections = this.selections.all::<usize>(cx);
10172            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10173                s.select(selections);
10174            });
10175        });
10176    }
10177
10178    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10179        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10180        self.rewrap_impl(RewrapOptions::default(), cx)
10181    }
10182
10183    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10184        let buffer = self.buffer.read(cx).snapshot(cx);
10185        let selections = self.selections.all::<Point>(cx);
10186        let mut selections = selections.iter().peekable();
10187
10188        let mut edits = Vec::new();
10189        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10190
10191        while let Some(selection) = selections.next() {
10192            let mut start_row = selection.start.row;
10193            let mut end_row = selection.end.row;
10194
10195            // Skip selections that overlap with a range that has already been rewrapped.
10196            let selection_range = start_row..end_row;
10197            if rewrapped_row_ranges
10198                .iter()
10199                .any(|range| range.overlaps(&selection_range))
10200            {
10201                continue;
10202            }
10203
10204            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10205
10206            // Since not all lines in the selection may be at the same indent
10207            // level, choose the indent size that is the most common between all
10208            // of the lines.
10209            //
10210            // If there is a tie, we use the deepest indent.
10211            let (indent_size, indent_end) = {
10212                let mut indent_size_occurrences = HashMap::default();
10213                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10214
10215                for row in start_row..=end_row {
10216                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10217                    rows_by_indent_size.entry(indent).or_default().push(row);
10218                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10219                }
10220
10221                let indent_size = indent_size_occurrences
10222                    .into_iter()
10223                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10224                    .map(|(indent, _)| indent)
10225                    .unwrap_or_default();
10226                let row = rows_by_indent_size[&indent_size][0];
10227                let indent_end = Point::new(row, indent_size.len);
10228
10229                (indent_size, indent_end)
10230            };
10231
10232            let mut line_prefix = indent_size.chars().collect::<String>();
10233
10234            let mut inside_comment = false;
10235            if let Some(comment_prefix) =
10236                buffer
10237                    .language_scope_at(selection.head())
10238                    .and_then(|language| {
10239                        language
10240                            .line_comment_prefixes()
10241                            .iter()
10242                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10243                            .cloned()
10244                    })
10245            {
10246                line_prefix.push_str(&comment_prefix);
10247                inside_comment = true;
10248            }
10249
10250            let language_settings = buffer.language_settings_at(selection.head(), cx);
10251            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10252                RewrapBehavior::InComments => inside_comment,
10253                RewrapBehavior::InSelections => !selection.is_empty(),
10254                RewrapBehavior::Anywhere => true,
10255            };
10256
10257            let should_rewrap = options.override_language_settings
10258                || allow_rewrap_based_on_language
10259                || self.hard_wrap.is_some();
10260            if !should_rewrap {
10261                continue;
10262            }
10263
10264            if selection.is_empty() {
10265                'expand_upwards: while start_row > 0 {
10266                    let prev_row = start_row - 1;
10267                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10268                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10269                    {
10270                        start_row = prev_row;
10271                    } else {
10272                        break 'expand_upwards;
10273                    }
10274                }
10275
10276                'expand_downwards: while end_row < buffer.max_point().row {
10277                    let next_row = end_row + 1;
10278                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10279                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10280                    {
10281                        end_row = next_row;
10282                    } else {
10283                        break 'expand_downwards;
10284                    }
10285                }
10286            }
10287
10288            let start = Point::new(start_row, 0);
10289            let start_offset = start.to_offset(&buffer);
10290            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10291            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10292            let Some(lines_without_prefixes) = selection_text
10293                .lines()
10294                .map(|line| {
10295                    line.strip_prefix(&line_prefix)
10296                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10297                        .ok_or_else(|| {
10298                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
10299                        })
10300                })
10301                .collect::<Result<Vec<_>, _>>()
10302                .log_err()
10303            else {
10304                continue;
10305            };
10306
10307            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10308                buffer
10309                    .language_settings_at(Point::new(start_row, 0), cx)
10310                    .preferred_line_length as usize
10311            });
10312            let wrapped_text = wrap_with_prefix(
10313                line_prefix,
10314                lines_without_prefixes.join("\n"),
10315                wrap_column,
10316                tab_size,
10317                options.preserve_existing_whitespace,
10318            );
10319
10320            // TODO: should always use char-based diff while still supporting cursor behavior that
10321            // matches vim.
10322            let mut diff_options = DiffOptions::default();
10323            if options.override_language_settings {
10324                diff_options.max_word_diff_len = 0;
10325                diff_options.max_word_diff_line_count = 0;
10326            } else {
10327                diff_options.max_word_diff_len = usize::MAX;
10328                diff_options.max_word_diff_line_count = usize::MAX;
10329            }
10330
10331            for (old_range, new_text) in
10332                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10333            {
10334                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10335                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10336                edits.push((edit_start..edit_end, new_text));
10337            }
10338
10339            rewrapped_row_ranges.push(start_row..=end_row);
10340        }
10341
10342        self.buffer
10343            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10344    }
10345
10346    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10347        let mut text = String::new();
10348        let buffer = self.buffer.read(cx).snapshot(cx);
10349        let mut selections = self.selections.all::<Point>(cx);
10350        let mut clipboard_selections = Vec::with_capacity(selections.len());
10351        {
10352            let max_point = buffer.max_point();
10353            let mut is_first = true;
10354            for selection in &mut selections {
10355                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10356                if is_entire_line {
10357                    selection.start = Point::new(selection.start.row, 0);
10358                    if !selection.is_empty() && selection.end.column == 0 {
10359                        selection.end = cmp::min(max_point, selection.end);
10360                    } else {
10361                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10362                    }
10363                    selection.goal = SelectionGoal::None;
10364                }
10365                if is_first {
10366                    is_first = false;
10367                } else {
10368                    text += "\n";
10369                }
10370                let mut len = 0;
10371                for chunk in buffer.text_for_range(selection.start..selection.end) {
10372                    text.push_str(chunk);
10373                    len += chunk.len();
10374                }
10375                clipboard_selections.push(ClipboardSelection {
10376                    len,
10377                    is_entire_line,
10378                    first_line_indent: buffer
10379                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10380                        .len,
10381                });
10382            }
10383        }
10384
10385        self.transact(window, cx, |this, window, cx| {
10386            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10387                s.select(selections);
10388            });
10389            this.insert("", window, cx);
10390        });
10391        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10392    }
10393
10394    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10395        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10396        let item = self.cut_common(window, cx);
10397        cx.write_to_clipboard(item);
10398    }
10399
10400    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10401        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10402        self.change_selections(None, window, cx, |s| {
10403            s.move_with(|snapshot, sel| {
10404                if sel.is_empty() {
10405                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10406                }
10407            });
10408        });
10409        let item = self.cut_common(window, cx);
10410        cx.set_global(KillRing(item))
10411    }
10412
10413    pub fn kill_ring_yank(
10414        &mut self,
10415        _: &KillRingYank,
10416        window: &mut Window,
10417        cx: &mut Context<Self>,
10418    ) {
10419        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10420        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10421            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10422                (kill_ring.text().to_string(), kill_ring.metadata_json())
10423            } else {
10424                return;
10425            }
10426        } else {
10427            return;
10428        };
10429        self.do_paste(&text, metadata, false, window, cx);
10430    }
10431
10432    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10433        self.do_copy(true, cx);
10434    }
10435
10436    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10437        self.do_copy(false, cx);
10438    }
10439
10440    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10441        let selections = self.selections.all::<Point>(cx);
10442        let buffer = self.buffer.read(cx).read(cx);
10443        let mut text = String::new();
10444
10445        let mut clipboard_selections = Vec::with_capacity(selections.len());
10446        {
10447            let max_point = buffer.max_point();
10448            let mut is_first = true;
10449            for selection in &selections {
10450                let mut start = selection.start;
10451                let mut end = selection.end;
10452                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10453                if is_entire_line {
10454                    start = Point::new(start.row, 0);
10455                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10456                }
10457
10458                let mut trimmed_selections = Vec::new();
10459                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10460                    let row = MultiBufferRow(start.row);
10461                    let first_indent = buffer.indent_size_for_line(row);
10462                    if first_indent.len == 0 || start.column > first_indent.len {
10463                        trimmed_selections.push(start..end);
10464                    } else {
10465                        trimmed_selections.push(
10466                            Point::new(row.0, first_indent.len)
10467                                ..Point::new(row.0, buffer.line_len(row)),
10468                        );
10469                        for row in start.row + 1..=end.row {
10470                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10471                            if row == end.row {
10472                                line_len = end.column;
10473                            }
10474                            if line_len == 0 {
10475                                trimmed_selections
10476                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10477                                continue;
10478                            }
10479                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10480                            if row_indent_size.len >= first_indent.len {
10481                                trimmed_selections.push(
10482                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10483                                );
10484                            } else {
10485                                trimmed_selections.clear();
10486                                trimmed_selections.push(start..end);
10487                                break;
10488                            }
10489                        }
10490                    }
10491                } else {
10492                    trimmed_selections.push(start..end);
10493                }
10494
10495                for trimmed_range in trimmed_selections {
10496                    if is_first {
10497                        is_first = false;
10498                    } else {
10499                        text += "\n";
10500                    }
10501                    let mut len = 0;
10502                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10503                        text.push_str(chunk);
10504                        len += chunk.len();
10505                    }
10506                    clipboard_selections.push(ClipboardSelection {
10507                        len,
10508                        is_entire_line,
10509                        first_line_indent: buffer
10510                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10511                            .len,
10512                    });
10513                }
10514            }
10515        }
10516
10517        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10518            text,
10519            clipboard_selections,
10520        ));
10521    }
10522
10523    pub fn do_paste(
10524        &mut self,
10525        text: &String,
10526        clipboard_selections: Option<Vec<ClipboardSelection>>,
10527        handle_entire_lines: bool,
10528        window: &mut Window,
10529        cx: &mut Context<Self>,
10530    ) {
10531        if self.read_only(cx) {
10532            return;
10533        }
10534
10535        let clipboard_text = Cow::Borrowed(text);
10536
10537        self.transact(window, cx, |this, window, cx| {
10538            if let Some(mut clipboard_selections) = clipboard_selections {
10539                let old_selections = this.selections.all::<usize>(cx);
10540                let all_selections_were_entire_line =
10541                    clipboard_selections.iter().all(|s| s.is_entire_line);
10542                let first_selection_indent_column =
10543                    clipboard_selections.first().map(|s| s.first_line_indent);
10544                if clipboard_selections.len() != old_selections.len() {
10545                    clipboard_selections.drain(..);
10546                }
10547                let cursor_offset = this.selections.last::<usize>(cx).head();
10548                let mut auto_indent_on_paste = true;
10549
10550                this.buffer.update(cx, |buffer, cx| {
10551                    let snapshot = buffer.read(cx);
10552                    auto_indent_on_paste = snapshot
10553                        .language_settings_at(cursor_offset, cx)
10554                        .auto_indent_on_paste;
10555
10556                    let mut start_offset = 0;
10557                    let mut edits = Vec::new();
10558                    let mut original_indent_columns = Vec::new();
10559                    for (ix, selection) in old_selections.iter().enumerate() {
10560                        let to_insert;
10561                        let entire_line;
10562                        let original_indent_column;
10563                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10564                            let end_offset = start_offset + clipboard_selection.len;
10565                            to_insert = &clipboard_text[start_offset..end_offset];
10566                            entire_line = clipboard_selection.is_entire_line;
10567                            start_offset = end_offset + 1;
10568                            original_indent_column = Some(clipboard_selection.first_line_indent);
10569                        } else {
10570                            to_insert = clipboard_text.as_str();
10571                            entire_line = all_selections_were_entire_line;
10572                            original_indent_column = first_selection_indent_column
10573                        }
10574
10575                        // If the corresponding selection was empty when this slice of the
10576                        // clipboard text was written, then the entire line containing the
10577                        // selection was copied. If this selection is also currently empty,
10578                        // then paste the line before the current line of the buffer.
10579                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10580                            let column = selection.start.to_point(&snapshot).column as usize;
10581                            let line_start = selection.start - column;
10582                            line_start..line_start
10583                        } else {
10584                            selection.range()
10585                        };
10586
10587                        edits.push((range, to_insert));
10588                        original_indent_columns.push(original_indent_column);
10589                    }
10590                    drop(snapshot);
10591
10592                    buffer.edit(
10593                        edits,
10594                        if auto_indent_on_paste {
10595                            Some(AutoindentMode::Block {
10596                                original_indent_columns,
10597                            })
10598                        } else {
10599                            None
10600                        },
10601                        cx,
10602                    );
10603                });
10604
10605                let selections = this.selections.all::<usize>(cx);
10606                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10607                    s.select(selections)
10608                });
10609            } else {
10610                this.insert(&clipboard_text, window, cx);
10611            }
10612        });
10613    }
10614
10615    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10616        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10617        if let Some(item) = cx.read_from_clipboard() {
10618            let entries = item.entries();
10619
10620            match entries.first() {
10621                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10622                // of all the pasted entries.
10623                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10624                    .do_paste(
10625                        clipboard_string.text(),
10626                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10627                        true,
10628                        window,
10629                        cx,
10630                    ),
10631                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10632            }
10633        }
10634    }
10635
10636    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10637        if self.read_only(cx) {
10638            return;
10639        }
10640
10641        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10642
10643        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10644            if let Some((selections, _)) =
10645                self.selection_history.transaction(transaction_id).cloned()
10646            {
10647                self.change_selections(None, window, cx, |s| {
10648                    s.select_anchors(selections.to_vec());
10649                });
10650            } else {
10651                log::error!(
10652                    "No entry in selection_history found for undo. \
10653                     This may correspond to a bug where undo does not update the selection. \
10654                     If this is occurring, please add details to \
10655                     https://github.com/zed-industries/zed/issues/22692"
10656                );
10657            }
10658            self.request_autoscroll(Autoscroll::fit(), cx);
10659            self.unmark_text(window, cx);
10660            self.refresh_inline_completion(true, false, window, cx);
10661            cx.emit(EditorEvent::Edited { transaction_id });
10662            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10663        }
10664    }
10665
10666    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
10667        if self.read_only(cx) {
10668            return;
10669        }
10670
10671        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10672
10673        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
10674            if let Some((_, Some(selections))) =
10675                self.selection_history.transaction(transaction_id).cloned()
10676            {
10677                self.change_selections(None, window, cx, |s| {
10678                    s.select_anchors(selections.to_vec());
10679                });
10680            } else {
10681                log::error!(
10682                    "No entry in selection_history found for redo. \
10683                     This may correspond to a bug where undo does not update the selection. \
10684                     If this is occurring, please add details to \
10685                     https://github.com/zed-industries/zed/issues/22692"
10686                );
10687            }
10688            self.request_autoscroll(Autoscroll::fit(), cx);
10689            self.unmark_text(window, cx);
10690            self.refresh_inline_completion(true, false, window, cx);
10691            cx.emit(EditorEvent::Edited { transaction_id });
10692        }
10693    }
10694
10695    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
10696        self.buffer
10697            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
10698    }
10699
10700    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
10701        self.buffer
10702            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
10703    }
10704
10705    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
10706        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10707        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10708            s.move_with(|map, selection| {
10709                let cursor = if selection.is_empty() {
10710                    movement::left(map, selection.start)
10711                } else {
10712                    selection.start
10713                };
10714                selection.collapse_to(cursor, SelectionGoal::None);
10715            });
10716        })
10717    }
10718
10719    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
10720        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10721        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10722            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
10723        })
10724    }
10725
10726    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
10727        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10728        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10729            s.move_with(|map, selection| {
10730                let cursor = if selection.is_empty() {
10731                    movement::right(map, selection.end)
10732                } else {
10733                    selection.end
10734                };
10735                selection.collapse_to(cursor, SelectionGoal::None)
10736            });
10737        })
10738    }
10739
10740    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
10741        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10742        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10743            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
10744        })
10745    }
10746
10747    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
10748        if self.take_rename(true, window, cx).is_some() {
10749            return;
10750        }
10751
10752        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10753            cx.propagate();
10754            return;
10755        }
10756
10757        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10758
10759        let text_layout_details = &self.text_layout_details(window);
10760        let selection_count = self.selections.count();
10761        let first_selection = self.selections.first_anchor();
10762
10763        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10764            s.move_with(|map, selection| {
10765                if !selection.is_empty() {
10766                    selection.goal = SelectionGoal::None;
10767                }
10768                let (cursor, goal) = movement::up(
10769                    map,
10770                    selection.start,
10771                    selection.goal,
10772                    false,
10773                    text_layout_details,
10774                );
10775                selection.collapse_to(cursor, goal);
10776            });
10777        });
10778
10779        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10780        {
10781            cx.propagate();
10782        }
10783    }
10784
10785    pub fn move_up_by_lines(
10786        &mut self,
10787        action: &MoveUpByLines,
10788        window: &mut Window,
10789        cx: &mut Context<Self>,
10790    ) {
10791        if self.take_rename(true, window, cx).is_some() {
10792            return;
10793        }
10794
10795        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10796            cx.propagate();
10797            return;
10798        }
10799
10800        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10801
10802        let text_layout_details = &self.text_layout_details(window);
10803
10804        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10805            s.move_with(|map, selection| {
10806                if !selection.is_empty() {
10807                    selection.goal = SelectionGoal::None;
10808                }
10809                let (cursor, goal) = movement::up_by_rows(
10810                    map,
10811                    selection.start,
10812                    action.lines,
10813                    selection.goal,
10814                    false,
10815                    text_layout_details,
10816                );
10817                selection.collapse_to(cursor, goal);
10818            });
10819        })
10820    }
10821
10822    pub fn move_down_by_lines(
10823        &mut self,
10824        action: &MoveDownByLines,
10825        window: &mut Window,
10826        cx: &mut Context<Self>,
10827    ) {
10828        if self.take_rename(true, window, cx).is_some() {
10829            return;
10830        }
10831
10832        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10833            cx.propagate();
10834            return;
10835        }
10836
10837        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10838
10839        let text_layout_details = &self.text_layout_details(window);
10840
10841        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10842            s.move_with(|map, selection| {
10843                if !selection.is_empty() {
10844                    selection.goal = SelectionGoal::None;
10845                }
10846                let (cursor, goal) = movement::down_by_rows(
10847                    map,
10848                    selection.start,
10849                    action.lines,
10850                    selection.goal,
10851                    false,
10852                    text_layout_details,
10853                );
10854                selection.collapse_to(cursor, goal);
10855            });
10856        })
10857    }
10858
10859    pub fn select_down_by_lines(
10860        &mut self,
10861        action: &SelectDownByLines,
10862        window: &mut Window,
10863        cx: &mut Context<Self>,
10864    ) {
10865        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10866        let text_layout_details = &self.text_layout_details(window);
10867        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10868            s.move_heads_with(|map, head, goal| {
10869                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
10870            })
10871        })
10872    }
10873
10874    pub fn select_up_by_lines(
10875        &mut self,
10876        action: &SelectUpByLines,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) {
10880        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10881        let text_layout_details = &self.text_layout_details(window);
10882        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10883            s.move_heads_with(|map, head, goal| {
10884                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
10885            })
10886        })
10887    }
10888
10889    pub fn select_page_up(
10890        &mut self,
10891        _: &SelectPageUp,
10892        window: &mut Window,
10893        cx: &mut Context<Self>,
10894    ) {
10895        let Some(row_count) = self.visible_row_count() else {
10896            return;
10897        };
10898
10899        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10900
10901        let text_layout_details = &self.text_layout_details(window);
10902
10903        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10904            s.move_heads_with(|map, head, goal| {
10905                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
10906            })
10907        })
10908    }
10909
10910    pub fn move_page_up(
10911        &mut self,
10912        action: &MovePageUp,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        if self.take_rename(true, window, cx).is_some() {
10917            return;
10918        }
10919
10920        if self
10921            .context_menu
10922            .borrow_mut()
10923            .as_mut()
10924            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
10925            .unwrap_or(false)
10926        {
10927            return;
10928        }
10929
10930        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10931            cx.propagate();
10932            return;
10933        }
10934
10935        let Some(row_count) = self.visible_row_count() else {
10936            return;
10937        };
10938
10939        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10940
10941        let autoscroll = if action.center_cursor {
10942            Autoscroll::center()
10943        } else {
10944            Autoscroll::fit()
10945        };
10946
10947        let text_layout_details = &self.text_layout_details(window);
10948
10949        self.change_selections(Some(autoscroll), 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_by_rows(
10955                    map,
10956                    selection.end,
10957                    row_count,
10958                    selection.goal,
10959                    false,
10960                    text_layout_details,
10961                );
10962                selection.collapse_to(cursor, goal);
10963            });
10964        });
10965    }
10966
10967    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
10968        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10969        let text_layout_details = &self.text_layout_details(window);
10970        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10971            s.move_heads_with(|map, head, goal| {
10972                movement::up(map, head, goal, false, text_layout_details)
10973            })
10974        })
10975    }
10976
10977    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
10978        self.take_rename(true, window, cx);
10979
10980        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10981            cx.propagate();
10982            return;
10983        }
10984
10985        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10986
10987        let text_layout_details = &self.text_layout_details(window);
10988        let selection_count = self.selections.count();
10989        let first_selection = self.selections.first_anchor();
10990
10991        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10992            s.move_with(|map, selection| {
10993                if !selection.is_empty() {
10994                    selection.goal = SelectionGoal::None;
10995                }
10996                let (cursor, goal) = movement::down(
10997                    map,
10998                    selection.end,
10999                    selection.goal,
11000                    false,
11001                    text_layout_details,
11002                );
11003                selection.collapse_to(cursor, goal);
11004            });
11005        });
11006
11007        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11008        {
11009            cx.propagate();
11010        }
11011    }
11012
11013    pub fn select_page_down(
11014        &mut self,
11015        _: &SelectPageDown,
11016        window: &mut Window,
11017        cx: &mut Context<Self>,
11018    ) {
11019        let Some(row_count) = self.visible_row_count() else {
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_heads_with(|map, head, goal| {
11029                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11030            })
11031        })
11032    }
11033
11034    pub fn move_page_down(
11035        &mut self,
11036        action: &MovePageDown,
11037        window: &mut Window,
11038        cx: &mut Context<Self>,
11039    ) {
11040        if self.take_rename(true, window, cx).is_some() {
11041            return;
11042        }
11043
11044        if self
11045            .context_menu
11046            .borrow_mut()
11047            .as_mut()
11048            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11049            .unwrap_or(false)
11050        {
11051            return;
11052        }
11053
11054        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11055            cx.propagate();
11056            return;
11057        }
11058
11059        let Some(row_count) = self.visible_row_count() else {
11060            return;
11061        };
11062
11063        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11064
11065        let autoscroll = if action.center_cursor {
11066            Autoscroll::center()
11067        } else {
11068            Autoscroll::fit()
11069        };
11070
11071        let text_layout_details = &self.text_layout_details(window);
11072        self.change_selections(Some(autoscroll), window, cx, |s| {
11073            s.move_with(|map, selection| {
11074                if !selection.is_empty() {
11075                    selection.goal = SelectionGoal::None;
11076                }
11077                let (cursor, goal) = movement::down_by_rows(
11078                    map,
11079                    selection.end,
11080                    row_count,
11081                    selection.goal,
11082                    false,
11083                    text_layout_details,
11084                );
11085                selection.collapse_to(cursor, goal);
11086            });
11087        });
11088    }
11089
11090    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11091        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11092        let text_layout_details = &self.text_layout_details(window);
11093        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11094            s.move_heads_with(|map, head, goal| {
11095                movement::down(map, head, goal, false, text_layout_details)
11096            })
11097        });
11098    }
11099
11100    pub fn context_menu_first(
11101        &mut self,
11102        _: &ContextMenuFirst,
11103        _window: &mut Window,
11104        cx: &mut Context<Self>,
11105    ) {
11106        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11107            context_menu.select_first(self.completion_provider.as_deref(), cx);
11108        }
11109    }
11110
11111    pub fn context_menu_prev(
11112        &mut self,
11113        _: &ContextMenuPrevious,
11114        _window: &mut Window,
11115        cx: &mut Context<Self>,
11116    ) {
11117        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11118            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11119        }
11120    }
11121
11122    pub fn context_menu_next(
11123        &mut self,
11124        _: &ContextMenuNext,
11125        _window: &mut Window,
11126        cx: &mut Context<Self>,
11127    ) {
11128        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11129            context_menu.select_next(self.completion_provider.as_deref(), cx);
11130        }
11131    }
11132
11133    pub fn context_menu_last(
11134        &mut self,
11135        _: &ContextMenuLast,
11136        _window: &mut Window,
11137        cx: &mut Context<Self>,
11138    ) {
11139        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11140            context_menu.select_last(self.completion_provider.as_deref(), cx);
11141        }
11142    }
11143
11144    pub fn move_to_previous_word_start(
11145        &mut self,
11146        _: &MoveToPreviousWordStart,
11147        window: &mut Window,
11148        cx: &mut Context<Self>,
11149    ) {
11150        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11151        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11152            s.move_cursors_with(|map, head, _| {
11153                (
11154                    movement::previous_word_start(map, head),
11155                    SelectionGoal::None,
11156                )
11157            });
11158        })
11159    }
11160
11161    pub fn move_to_previous_subword_start(
11162        &mut self,
11163        _: &MoveToPreviousSubwordStart,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166    ) {
11167        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11168        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11169            s.move_cursors_with(|map, head, _| {
11170                (
11171                    movement::previous_subword_start(map, head),
11172                    SelectionGoal::None,
11173                )
11174            });
11175        })
11176    }
11177
11178    pub fn select_to_previous_word_start(
11179        &mut self,
11180        _: &SelectToPreviousWordStart,
11181        window: &mut Window,
11182        cx: &mut Context<Self>,
11183    ) {
11184        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11185        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11186            s.move_heads_with(|map, head, _| {
11187                (
11188                    movement::previous_word_start(map, head),
11189                    SelectionGoal::None,
11190                )
11191            });
11192        })
11193    }
11194
11195    pub fn select_to_previous_subword_start(
11196        &mut self,
11197        _: &SelectToPreviousSubwordStart,
11198        window: &mut Window,
11199        cx: &mut Context<Self>,
11200    ) {
11201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11202        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11203            s.move_heads_with(|map, head, _| {
11204                (
11205                    movement::previous_subword_start(map, head),
11206                    SelectionGoal::None,
11207                )
11208            });
11209        })
11210    }
11211
11212    pub fn delete_to_previous_word_start(
11213        &mut self,
11214        action: &DeleteToPreviousWordStart,
11215        window: &mut Window,
11216        cx: &mut Context<Self>,
11217    ) {
11218        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11219        self.transact(window, cx, |this, window, cx| {
11220            this.select_autoclose_pair(window, cx);
11221            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11222                s.move_with(|map, selection| {
11223                    if selection.is_empty() {
11224                        let cursor = if action.ignore_newlines {
11225                            movement::previous_word_start(map, selection.head())
11226                        } else {
11227                            movement::previous_word_start_or_newline(map, selection.head())
11228                        };
11229                        selection.set_head(cursor, SelectionGoal::None);
11230                    }
11231                });
11232            });
11233            this.insert("", window, cx);
11234        });
11235    }
11236
11237    pub fn delete_to_previous_subword_start(
11238        &mut self,
11239        _: &DeleteToPreviousSubwordStart,
11240        window: &mut Window,
11241        cx: &mut Context<Self>,
11242    ) {
11243        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11244        self.transact(window, cx, |this, window, cx| {
11245            this.select_autoclose_pair(window, cx);
11246            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11247                s.move_with(|map, selection| {
11248                    if selection.is_empty() {
11249                        let cursor = movement::previous_subword_start(map, selection.head());
11250                        selection.set_head(cursor, SelectionGoal::None);
11251                    }
11252                });
11253            });
11254            this.insert("", window, cx);
11255        });
11256    }
11257
11258    pub fn move_to_next_word_end(
11259        &mut self,
11260        _: &MoveToNextWordEnd,
11261        window: &mut Window,
11262        cx: &mut Context<Self>,
11263    ) {
11264        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11265        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11266            s.move_cursors_with(|map, head, _| {
11267                (movement::next_word_end(map, head), SelectionGoal::None)
11268            });
11269        })
11270    }
11271
11272    pub fn move_to_next_subword_end(
11273        &mut self,
11274        _: &MoveToNextSubwordEnd,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277    ) {
11278        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11279        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11280            s.move_cursors_with(|map, head, _| {
11281                (movement::next_subword_end(map, head), SelectionGoal::None)
11282            });
11283        })
11284    }
11285
11286    pub fn select_to_next_word_end(
11287        &mut self,
11288        _: &SelectToNextWordEnd,
11289        window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11293        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11294            s.move_heads_with(|map, head, _| {
11295                (movement::next_word_end(map, head), SelectionGoal::None)
11296            });
11297        })
11298    }
11299
11300    pub fn select_to_next_subword_end(
11301        &mut self,
11302        _: &SelectToNextSubwordEnd,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11307        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11308            s.move_heads_with(|map, head, _| {
11309                (movement::next_subword_end(map, head), SelectionGoal::None)
11310            });
11311        })
11312    }
11313
11314    pub fn delete_to_next_word_end(
11315        &mut self,
11316        action: &DeleteToNextWordEnd,
11317        window: &mut Window,
11318        cx: &mut Context<Self>,
11319    ) {
11320        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11321        self.transact(window, cx, |this, window, cx| {
11322            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11323                s.move_with(|map, selection| {
11324                    if selection.is_empty() {
11325                        let cursor = if action.ignore_newlines {
11326                            movement::next_word_end(map, selection.head())
11327                        } else {
11328                            movement::next_word_end_or_newline(map, selection.head())
11329                        };
11330                        selection.set_head(cursor, SelectionGoal::None);
11331                    }
11332                });
11333            });
11334            this.insert("", window, cx);
11335        });
11336    }
11337
11338    pub fn delete_to_next_subword_end(
11339        &mut self,
11340        _: &DeleteToNextSubwordEnd,
11341        window: &mut Window,
11342        cx: &mut Context<Self>,
11343    ) {
11344        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11345        self.transact(window, cx, |this, window, cx| {
11346            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11347                s.move_with(|map, selection| {
11348                    if selection.is_empty() {
11349                        let cursor = movement::next_subword_end(map, selection.head());
11350                        selection.set_head(cursor, SelectionGoal::None);
11351                    }
11352                });
11353            });
11354            this.insert("", window, cx);
11355        });
11356    }
11357
11358    pub fn move_to_beginning_of_line(
11359        &mut self,
11360        action: &MoveToBeginningOfLine,
11361        window: &mut Window,
11362        cx: &mut Context<Self>,
11363    ) {
11364        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11365        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11366            s.move_cursors_with(|map, head, _| {
11367                (
11368                    movement::indented_line_beginning(
11369                        map,
11370                        head,
11371                        action.stop_at_soft_wraps,
11372                        action.stop_at_indent,
11373                    ),
11374                    SelectionGoal::None,
11375                )
11376            });
11377        })
11378    }
11379
11380    pub fn select_to_beginning_of_line(
11381        &mut self,
11382        action: &SelectToBeginningOfLine,
11383        window: &mut Window,
11384        cx: &mut Context<Self>,
11385    ) {
11386        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11387        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11388            s.move_heads_with(|map, head, _| {
11389                (
11390                    movement::indented_line_beginning(
11391                        map,
11392                        head,
11393                        action.stop_at_soft_wraps,
11394                        action.stop_at_indent,
11395                    ),
11396                    SelectionGoal::None,
11397                )
11398            });
11399        });
11400    }
11401
11402    pub fn delete_to_beginning_of_line(
11403        &mut self,
11404        action: &DeleteToBeginningOfLine,
11405        window: &mut Window,
11406        cx: &mut Context<Self>,
11407    ) {
11408        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11409        self.transact(window, cx, |this, window, cx| {
11410            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11411                s.move_with(|_, selection| {
11412                    selection.reversed = true;
11413                });
11414            });
11415
11416            this.select_to_beginning_of_line(
11417                &SelectToBeginningOfLine {
11418                    stop_at_soft_wraps: false,
11419                    stop_at_indent: action.stop_at_indent,
11420                },
11421                window,
11422                cx,
11423            );
11424            this.backspace(&Backspace, window, cx);
11425        });
11426    }
11427
11428    pub fn move_to_end_of_line(
11429        &mut self,
11430        action: &MoveToEndOfLine,
11431        window: &mut Window,
11432        cx: &mut Context<Self>,
11433    ) {
11434        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11435        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11436            s.move_cursors_with(|map, head, _| {
11437                (
11438                    movement::line_end(map, head, action.stop_at_soft_wraps),
11439                    SelectionGoal::None,
11440                )
11441            });
11442        })
11443    }
11444
11445    pub fn select_to_end_of_line(
11446        &mut self,
11447        action: &SelectToEndOfLine,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11452        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11453            s.move_heads_with(|map, head, _| {
11454                (
11455                    movement::line_end(map, head, action.stop_at_soft_wraps),
11456                    SelectionGoal::None,
11457                )
11458            });
11459        })
11460    }
11461
11462    pub fn delete_to_end_of_line(
11463        &mut self,
11464        _: &DeleteToEndOfLine,
11465        window: &mut Window,
11466        cx: &mut Context<Self>,
11467    ) {
11468        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11469        self.transact(window, cx, |this, window, cx| {
11470            this.select_to_end_of_line(
11471                &SelectToEndOfLine {
11472                    stop_at_soft_wraps: false,
11473                },
11474                window,
11475                cx,
11476            );
11477            this.delete(&Delete, window, cx);
11478        });
11479    }
11480
11481    pub fn cut_to_end_of_line(
11482        &mut self,
11483        _: &CutToEndOfLine,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11488        self.transact(window, cx, |this, window, cx| {
11489            this.select_to_end_of_line(
11490                &SelectToEndOfLine {
11491                    stop_at_soft_wraps: false,
11492                },
11493                window,
11494                cx,
11495            );
11496            this.cut(&Cut, window, cx);
11497        });
11498    }
11499
11500    pub fn move_to_start_of_paragraph(
11501        &mut self,
11502        _: &MoveToStartOfParagraph,
11503        window: &mut Window,
11504        cx: &mut Context<Self>,
11505    ) {
11506        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11507            cx.propagate();
11508            return;
11509        }
11510        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11511        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11512            s.move_with(|map, selection| {
11513                selection.collapse_to(
11514                    movement::start_of_paragraph(map, selection.head(), 1),
11515                    SelectionGoal::None,
11516                )
11517            });
11518        })
11519    }
11520
11521    pub fn move_to_end_of_paragraph(
11522        &mut self,
11523        _: &MoveToEndOfParagraph,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11528            cx.propagate();
11529            return;
11530        }
11531        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11532        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11533            s.move_with(|map, selection| {
11534                selection.collapse_to(
11535                    movement::end_of_paragraph(map, selection.head(), 1),
11536                    SelectionGoal::None,
11537                )
11538            });
11539        })
11540    }
11541
11542    pub fn select_to_start_of_paragraph(
11543        &mut self,
11544        _: &SelectToStartOfParagraph,
11545        window: &mut Window,
11546        cx: &mut Context<Self>,
11547    ) {
11548        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11549            cx.propagate();
11550            return;
11551        }
11552        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11553        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11554            s.move_heads_with(|map, head, _| {
11555                (
11556                    movement::start_of_paragraph(map, head, 1),
11557                    SelectionGoal::None,
11558                )
11559            });
11560        })
11561    }
11562
11563    pub fn select_to_end_of_paragraph(
11564        &mut self,
11565        _: &SelectToEndOfParagraph,
11566        window: &mut Window,
11567        cx: &mut Context<Self>,
11568    ) {
11569        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11570            cx.propagate();
11571            return;
11572        }
11573        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11574        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11575            s.move_heads_with(|map, head, _| {
11576                (
11577                    movement::end_of_paragraph(map, head, 1),
11578                    SelectionGoal::None,
11579                )
11580            });
11581        })
11582    }
11583
11584    pub fn move_to_start_of_excerpt(
11585        &mut self,
11586        _: &MoveToStartOfExcerpt,
11587        window: &mut Window,
11588        cx: &mut Context<Self>,
11589    ) {
11590        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11591            cx.propagate();
11592            return;
11593        }
11594        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11595        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11596            s.move_with(|map, selection| {
11597                selection.collapse_to(
11598                    movement::start_of_excerpt(
11599                        map,
11600                        selection.head(),
11601                        workspace::searchable::Direction::Prev,
11602                    ),
11603                    SelectionGoal::None,
11604                )
11605            });
11606        })
11607    }
11608
11609    pub fn move_to_start_of_next_excerpt(
11610        &mut self,
11611        _: &MoveToStartOfNextExcerpt,
11612        window: &mut Window,
11613        cx: &mut Context<Self>,
11614    ) {
11615        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11616            cx.propagate();
11617            return;
11618        }
11619
11620        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11621            s.move_with(|map, selection| {
11622                selection.collapse_to(
11623                    movement::start_of_excerpt(
11624                        map,
11625                        selection.head(),
11626                        workspace::searchable::Direction::Next,
11627                    ),
11628                    SelectionGoal::None,
11629                )
11630            });
11631        })
11632    }
11633
11634    pub fn move_to_end_of_excerpt(
11635        &mut self,
11636        _: &MoveToEndOfExcerpt,
11637        window: &mut Window,
11638        cx: &mut Context<Self>,
11639    ) {
11640        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11641            cx.propagate();
11642            return;
11643        }
11644        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11645        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11646            s.move_with(|map, selection| {
11647                selection.collapse_to(
11648                    movement::end_of_excerpt(
11649                        map,
11650                        selection.head(),
11651                        workspace::searchable::Direction::Next,
11652                    ),
11653                    SelectionGoal::None,
11654                )
11655            });
11656        })
11657    }
11658
11659    pub fn move_to_end_of_previous_excerpt(
11660        &mut self,
11661        _: &MoveToEndOfPreviousExcerpt,
11662        window: &mut Window,
11663        cx: &mut Context<Self>,
11664    ) {
11665        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11666            cx.propagate();
11667            return;
11668        }
11669        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11670        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11671            s.move_with(|map, selection| {
11672                selection.collapse_to(
11673                    movement::end_of_excerpt(
11674                        map,
11675                        selection.head(),
11676                        workspace::searchable::Direction::Prev,
11677                    ),
11678                    SelectionGoal::None,
11679                )
11680            });
11681        })
11682    }
11683
11684    pub fn select_to_start_of_excerpt(
11685        &mut self,
11686        _: &SelectToStartOfExcerpt,
11687        window: &mut Window,
11688        cx: &mut Context<Self>,
11689    ) {
11690        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11691            cx.propagate();
11692            return;
11693        }
11694        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11695        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11696            s.move_heads_with(|map, head, _| {
11697                (
11698                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11699                    SelectionGoal::None,
11700                )
11701            });
11702        })
11703    }
11704
11705    pub fn select_to_start_of_next_excerpt(
11706        &mut self,
11707        _: &SelectToStartOfNextExcerpt,
11708        window: &mut Window,
11709        cx: &mut Context<Self>,
11710    ) {
11711        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11712            cx.propagate();
11713            return;
11714        }
11715        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11716        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11717            s.move_heads_with(|map, head, _| {
11718                (
11719                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
11720                    SelectionGoal::None,
11721                )
11722            });
11723        })
11724    }
11725
11726    pub fn select_to_end_of_excerpt(
11727        &mut self,
11728        _: &SelectToEndOfExcerpt,
11729        window: &mut Window,
11730        cx: &mut Context<Self>,
11731    ) {
11732        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11733            cx.propagate();
11734            return;
11735        }
11736        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11737        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11738            s.move_heads_with(|map, head, _| {
11739                (
11740                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
11741                    SelectionGoal::None,
11742                )
11743            });
11744        })
11745    }
11746
11747    pub fn select_to_end_of_previous_excerpt(
11748        &mut self,
11749        _: &SelectToEndOfPreviousExcerpt,
11750        window: &mut Window,
11751        cx: &mut Context<Self>,
11752    ) {
11753        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11754            cx.propagate();
11755            return;
11756        }
11757        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11758        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11759            s.move_heads_with(|map, head, _| {
11760                (
11761                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11762                    SelectionGoal::None,
11763                )
11764            });
11765        })
11766    }
11767
11768    pub fn move_to_beginning(
11769        &mut self,
11770        _: &MoveToBeginning,
11771        window: &mut Window,
11772        cx: &mut Context<Self>,
11773    ) {
11774        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11775            cx.propagate();
11776            return;
11777        }
11778        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11779        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11780            s.select_ranges(vec![0..0]);
11781        });
11782    }
11783
11784    pub fn select_to_beginning(
11785        &mut self,
11786        _: &SelectToBeginning,
11787        window: &mut Window,
11788        cx: &mut Context<Self>,
11789    ) {
11790        let mut selection = self.selections.last::<Point>(cx);
11791        selection.set_head(Point::zero(), SelectionGoal::None);
11792        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11793        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11794            s.select(vec![selection]);
11795        });
11796    }
11797
11798    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
11799        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11800            cx.propagate();
11801            return;
11802        }
11803        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11804        let cursor = self.buffer.read(cx).read(cx).len();
11805        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11806            s.select_ranges(vec![cursor..cursor])
11807        });
11808    }
11809
11810    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
11811        self.nav_history = nav_history;
11812    }
11813
11814    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
11815        self.nav_history.as_ref()
11816    }
11817
11818    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
11819        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
11820    }
11821
11822    fn push_to_nav_history(
11823        &mut self,
11824        cursor_anchor: Anchor,
11825        new_position: Option<Point>,
11826        is_deactivate: bool,
11827        cx: &mut Context<Self>,
11828    ) {
11829        if let Some(nav_history) = self.nav_history.as_mut() {
11830            let buffer = self.buffer.read(cx).read(cx);
11831            let cursor_position = cursor_anchor.to_point(&buffer);
11832            let scroll_state = self.scroll_manager.anchor();
11833            let scroll_top_row = scroll_state.top_row(&buffer);
11834            drop(buffer);
11835
11836            if let Some(new_position) = new_position {
11837                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
11838                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
11839                    return;
11840                }
11841            }
11842
11843            nav_history.push(
11844                Some(NavigationData {
11845                    cursor_anchor,
11846                    cursor_position,
11847                    scroll_anchor: scroll_state,
11848                    scroll_top_row,
11849                }),
11850                cx,
11851            );
11852            cx.emit(EditorEvent::PushedToNavHistory {
11853                anchor: cursor_anchor,
11854                is_deactivate,
11855            })
11856        }
11857    }
11858
11859    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
11860        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11861        let buffer = self.buffer.read(cx).snapshot(cx);
11862        let mut selection = self.selections.first::<usize>(cx);
11863        selection.set_head(buffer.len(), SelectionGoal::None);
11864        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11865            s.select(vec![selection]);
11866        });
11867    }
11868
11869    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
11870        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11871        let end = self.buffer.read(cx).read(cx).len();
11872        self.change_selections(None, window, cx, |s| {
11873            s.select_ranges(vec![0..end]);
11874        });
11875    }
11876
11877    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
11878        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11879        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11880        let mut selections = self.selections.all::<Point>(cx);
11881        let max_point = display_map.buffer_snapshot.max_point();
11882        for selection in &mut selections {
11883            let rows = selection.spanned_rows(true, &display_map);
11884            selection.start = Point::new(rows.start.0, 0);
11885            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
11886            selection.reversed = false;
11887        }
11888        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11889            s.select(selections);
11890        });
11891    }
11892
11893    pub fn split_selection_into_lines(
11894        &mut self,
11895        _: &SplitSelectionIntoLines,
11896        window: &mut Window,
11897        cx: &mut Context<Self>,
11898    ) {
11899        let selections = self
11900            .selections
11901            .all::<Point>(cx)
11902            .into_iter()
11903            .map(|selection| selection.start..selection.end)
11904            .collect::<Vec<_>>();
11905        self.unfold_ranges(&selections, true, true, cx);
11906
11907        let mut new_selection_ranges = Vec::new();
11908        {
11909            let buffer = self.buffer.read(cx).read(cx);
11910            for selection in selections {
11911                for row in selection.start.row..selection.end.row {
11912                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11913                    new_selection_ranges.push(cursor..cursor);
11914                }
11915
11916                let is_multiline_selection = selection.start.row != selection.end.row;
11917                // Don't insert last one if it's a multi-line selection ending at the start of a line,
11918                // so this action feels more ergonomic when paired with other selection operations
11919                let should_skip_last = is_multiline_selection && selection.end.column == 0;
11920                if !should_skip_last {
11921                    new_selection_ranges.push(selection.end..selection.end);
11922                }
11923            }
11924        }
11925        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11926            s.select_ranges(new_selection_ranges);
11927        });
11928    }
11929
11930    pub fn add_selection_above(
11931        &mut self,
11932        _: &AddSelectionAbove,
11933        window: &mut Window,
11934        cx: &mut Context<Self>,
11935    ) {
11936        self.add_selection(true, window, cx);
11937    }
11938
11939    pub fn add_selection_below(
11940        &mut self,
11941        _: &AddSelectionBelow,
11942        window: &mut Window,
11943        cx: &mut Context<Self>,
11944    ) {
11945        self.add_selection(false, window, cx);
11946    }
11947
11948    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
11949        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11950
11951        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11952        let mut selections = self.selections.all::<Point>(cx);
11953        let text_layout_details = self.text_layout_details(window);
11954        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
11955            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
11956            let range = oldest_selection.display_range(&display_map).sorted();
11957
11958            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
11959            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
11960            let positions = start_x.min(end_x)..start_x.max(end_x);
11961
11962            selections.clear();
11963            let mut stack = Vec::new();
11964            for row in range.start.row().0..=range.end.row().0 {
11965                if let Some(selection) = self.selections.build_columnar_selection(
11966                    &display_map,
11967                    DisplayRow(row),
11968                    &positions,
11969                    oldest_selection.reversed,
11970                    &text_layout_details,
11971                ) {
11972                    stack.push(selection.id);
11973                    selections.push(selection);
11974                }
11975            }
11976
11977            if above {
11978                stack.reverse();
11979            }
11980
11981            AddSelectionsState { above, stack }
11982        });
11983
11984        let last_added_selection = *state.stack.last().unwrap();
11985        let mut new_selections = Vec::new();
11986        if above == state.above {
11987            let end_row = if above {
11988                DisplayRow(0)
11989            } else {
11990                display_map.max_point().row()
11991            };
11992
11993            'outer: for selection in selections {
11994                if selection.id == last_added_selection {
11995                    let range = selection.display_range(&display_map).sorted();
11996                    debug_assert_eq!(range.start.row(), range.end.row());
11997                    let mut row = range.start.row();
11998                    let positions =
11999                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12000                            px(start)..px(end)
12001                        } else {
12002                            let start_x =
12003                                display_map.x_for_display_point(range.start, &text_layout_details);
12004                            let end_x =
12005                                display_map.x_for_display_point(range.end, &text_layout_details);
12006                            start_x.min(end_x)..start_x.max(end_x)
12007                        };
12008
12009                    while row != end_row {
12010                        if above {
12011                            row.0 -= 1;
12012                        } else {
12013                            row.0 += 1;
12014                        }
12015
12016                        if let Some(new_selection) = self.selections.build_columnar_selection(
12017                            &display_map,
12018                            row,
12019                            &positions,
12020                            selection.reversed,
12021                            &text_layout_details,
12022                        ) {
12023                            state.stack.push(new_selection.id);
12024                            if above {
12025                                new_selections.push(new_selection);
12026                                new_selections.push(selection);
12027                            } else {
12028                                new_selections.push(selection);
12029                                new_selections.push(new_selection);
12030                            }
12031
12032                            continue 'outer;
12033                        }
12034                    }
12035                }
12036
12037                new_selections.push(selection);
12038            }
12039        } else {
12040            new_selections = selections;
12041            new_selections.retain(|s| s.id != last_added_selection);
12042            state.stack.pop();
12043        }
12044
12045        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12046            s.select(new_selections);
12047        });
12048        if state.stack.len() > 1 {
12049            self.add_selections_state = Some(state);
12050        }
12051    }
12052
12053    pub fn select_next_match_internal(
12054        &mut self,
12055        display_map: &DisplaySnapshot,
12056        replace_newest: bool,
12057        autoscroll: Option<Autoscroll>,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) -> Result<()> {
12061        fn select_next_match_ranges(
12062            this: &mut Editor,
12063            range: Range<usize>,
12064            reversed: bool,
12065            replace_newest: bool,
12066            auto_scroll: Option<Autoscroll>,
12067            window: &mut Window,
12068            cx: &mut Context<Editor>,
12069        ) {
12070            this.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12071            this.change_selections(auto_scroll, window, cx, |s| {
12072                if replace_newest {
12073                    s.delete(s.newest_anchor().id);
12074                }
12075                if reversed {
12076                    s.insert_range(range.end..range.start);
12077                } else {
12078                    s.insert_range(range);
12079                }
12080            });
12081        }
12082
12083        let buffer = &display_map.buffer_snapshot;
12084        let mut selections = self.selections.all::<usize>(cx);
12085        if let Some(mut select_next_state) = self.select_next_state.take() {
12086            let query = &select_next_state.query;
12087            if !select_next_state.done {
12088                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12089                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12090                let mut next_selected_range = None;
12091
12092                let bytes_after_last_selection =
12093                    buffer.bytes_in_range(last_selection.end..buffer.len());
12094                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12095                let query_matches = query
12096                    .stream_find_iter(bytes_after_last_selection)
12097                    .map(|result| (last_selection.end, result))
12098                    .chain(
12099                        query
12100                            .stream_find_iter(bytes_before_first_selection)
12101                            .map(|result| (0, result)),
12102                    );
12103
12104                for (start_offset, query_match) in query_matches {
12105                    let query_match = query_match.unwrap(); // can only fail due to I/O
12106                    let offset_range =
12107                        start_offset + query_match.start()..start_offset + query_match.end();
12108                    let display_range = offset_range.start.to_display_point(display_map)
12109                        ..offset_range.end.to_display_point(display_map);
12110
12111                    if !select_next_state.wordwise
12112                        || (!movement::is_inside_word(display_map, display_range.start)
12113                            && !movement::is_inside_word(display_map, display_range.end))
12114                    {
12115                        // TODO: This is n^2, because we might check all the selections
12116                        if !selections
12117                            .iter()
12118                            .any(|selection| selection.range().overlaps(&offset_range))
12119                        {
12120                            next_selected_range = Some(offset_range);
12121                            break;
12122                        }
12123                    }
12124                }
12125
12126                if let Some(next_selected_range) = next_selected_range {
12127                    select_next_match_ranges(
12128                        self,
12129                        next_selected_range,
12130                        last_selection.reversed,
12131                        replace_newest,
12132                        autoscroll,
12133                        window,
12134                        cx,
12135                    );
12136                } else {
12137                    select_next_state.done = true;
12138                }
12139            }
12140
12141            self.select_next_state = Some(select_next_state);
12142        } else {
12143            let mut only_carets = true;
12144            let mut same_text_selected = true;
12145            let mut selected_text = None;
12146
12147            let mut selections_iter = selections.iter().peekable();
12148            while let Some(selection) = selections_iter.next() {
12149                if selection.start != selection.end {
12150                    only_carets = false;
12151                }
12152
12153                if same_text_selected {
12154                    if selected_text.is_none() {
12155                        selected_text =
12156                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12157                    }
12158
12159                    if let Some(next_selection) = selections_iter.peek() {
12160                        if next_selection.range().len() == selection.range().len() {
12161                            let next_selected_text = buffer
12162                                .text_for_range(next_selection.range())
12163                                .collect::<String>();
12164                            if Some(next_selected_text) != selected_text {
12165                                same_text_selected = false;
12166                                selected_text = None;
12167                            }
12168                        } else {
12169                            same_text_selected = false;
12170                            selected_text = None;
12171                        }
12172                    }
12173                }
12174            }
12175
12176            if only_carets {
12177                for selection in &mut selections {
12178                    let word_range = movement::surrounding_word(
12179                        display_map,
12180                        selection.start.to_display_point(display_map),
12181                    );
12182                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12183                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12184                    selection.goal = SelectionGoal::None;
12185                    selection.reversed = false;
12186                    select_next_match_ranges(
12187                        self,
12188                        selection.start..selection.end,
12189                        selection.reversed,
12190                        replace_newest,
12191                        autoscroll,
12192                        window,
12193                        cx,
12194                    );
12195                }
12196
12197                if selections.len() == 1 {
12198                    let selection = selections
12199                        .last()
12200                        .expect("ensured that there's only one selection");
12201                    let query = buffer
12202                        .text_for_range(selection.start..selection.end)
12203                        .collect::<String>();
12204                    let is_empty = query.is_empty();
12205                    let select_state = SelectNextState {
12206                        query: AhoCorasick::new(&[query])?,
12207                        wordwise: true,
12208                        done: is_empty,
12209                    };
12210                    self.select_next_state = Some(select_state);
12211                } else {
12212                    self.select_next_state = None;
12213                }
12214            } else if let Some(selected_text) = selected_text {
12215                self.select_next_state = Some(SelectNextState {
12216                    query: AhoCorasick::new(&[selected_text])?,
12217                    wordwise: false,
12218                    done: false,
12219                });
12220                self.select_next_match_internal(
12221                    display_map,
12222                    replace_newest,
12223                    autoscroll,
12224                    window,
12225                    cx,
12226                )?;
12227            }
12228        }
12229        Ok(())
12230    }
12231
12232    pub fn select_all_matches(
12233        &mut self,
12234        _action: &SelectAllMatches,
12235        window: &mut Window,
12236        cx: &mut Context<Self>,
12237    ) -> Result<()> {
12238        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12239
12240        self.push_to_selection_history();
12241        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12242
12243        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12244        let Some(select_next_state) = self.select_next_state.as_mut() else {
12245            return Ok(());
12246        };
12247        if select_next_state.done {
12248            return Ok(());
12249        }
12250
12251        let mut new_selections = Vec::new();
12252
12253        let reversed = self.selections.oldest::<usize>(cx).reversed;
12254        let buffer = &display_map.buffer_snapshot;
12255        let query_matches = select_next_state
12256            .query
12257            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12258
12259        for query_match in query_matches.into_iter() {
12260            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12261            let offset_range = if reversed {
12262                query_match.end()..query_match.start()
12263            } else {
12264                query_match.start()..query_match.end()
12265            };
12266            let display_range = offset_range.start.to_display_point(&display_map)
12267                ..offset_range.end.to_display_point(&display_map);
12268
12269            if !select_next_state.wordwise
12270                || (!movement::is_inside_word(&display_map, display_range.start)
12271                    && !movement::is_inside_word(&display_map, display_range.end))
12272            {
12273                new_selections.push(offset_range.start..offset_range.end);
12274            }
12275        }
12276
12277        select_next_state.done = true;
12278        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12279        self.change_selections(None, window, cx, |selections| {
12280            selections.select_ranges(new_selections)
12281        });
12282
12283        Ok(())
12284    }
12285
12286    pub fn select_next(
12287        &mut self,
12288        action: &SelectNext,
12289        window: &mut Window,
12290        cx: &mut Context<Self>,
12291    ) -> Result<()> {
12292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12293        self.push_to_selection_history();
12294        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12295        self.select_next_match_internal(
12296            &display_map,
12297            action.replace_newest,
12298            Some(Autoscroll::newest()),
12299            window,
12300            cx,
12301        )?;
12302        Ok(())
12303    }
12304
12305    pub fn select_previous(
12306        &mut self,
12307        action: &SelectPrevious,
12308        window: &mut Window,
12309        cx: &mut Context<Self>,
12310    ) -> Result<()> {
12311        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12312        self.push_to_selection_history();
12313        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12314        let buffer = &display_map.buffer_snapshot;
12315        let mut selections = self.selections.all::<usize>(cx);
12316        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12317            let query = &select_prev_state.query;
12318            if !select_prev_state.done {
12319                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12320                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12321                let mut next_selected_range = None;
12322                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12323                let bytes_before_last_selection =
12324                    buffer.reversed_bytes_in_range(0..last_selection.start);
12325                let bytes_after_first_selection =
12326                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12327                let query_matches = query
12328                    .stream_find_iter(bytes_before_last_selection)
12329                    .map(|result| (last_selection.start, result))
12330                    .chain(
12331                        query
12332                            .stream_find_iter(bytes_after_first_selection)
12333                            .map(|result| (buffer.len(), result)),
12334                    );
12335                for (end_offset, query_match) in query_matches {
12336                    let query_match = query_match.unwrap(); // can only fail due to I/O
12337                    let offset_range =
12338                        end_offset - query_match.end()..end_offset - query_match.start();
12339                    let display_range = offset_range.start.to_display_point(&display_map)
12340                        ..offset_range.end.to_display_point(&display_map);
12341
12342                    if !select_prev_state.wordwise
12343                        || (!movement::is_inside_word(&display_map, display_range.start)
12344                            && !movement::is_inside_word(&display_map, display_range.end))
12345                    {
12346                        next_selected_range = Some(offset_range);
12347                        break;
12348                    }
12349                }
12350
12351                if let Some(next_selected_range) = next_selected_range {
12352                    self.unfold_ranges(&[next_selected_range.clone()], false, true, cx);
12353                    self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
12354                        if action.replace_newest {
12355                            s.delete(s.newest_anchor().id);
12356                        }
12357                        if last_selection.reversed {
12358                            s.insert_range(next_selected_range.end..next_selected_range.start);
12359                        } else {
12360                            s.insert_range(next_selected_range);
12361                        }
12362                    });
12363                } else {
12364                    select_prev_state.done = true;
12365                }
12366            }
12367
12368            self.select_prev_state = Some(select_prev_state);
12369        } else {
12370            let mut only_carets = true;
12371            let mut same_text_selected = true;
12372            let mut selected_text = None;
12373
12374            let mut selections_iter = selections.iter().peekable();
12375            while let Some(selection) = selections_iter.next() {
12376                if selection.start != selection.end {
12377                    only_carets = false;
12378                }
12379
12380                if same_text_selected {
12381                    if selected_text.is_none() {
12382                        selected_text =
12383                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12384                    }
12385
12386                    if let Some(next_selection) = selections_iter.peek() {
12387                        if next_selection.range().len() == selection.range().len() {
12388                            let next_selected_text = buffer
12389                                .text_for_range(next_selection.range())
12390                                .collect::<String>();
12391                            if Some(next_selected_text) != selected_text {
12392                                same_text_selected = false;
12393                                selected_text = None;
12394                            }
12395                        } else {
12396                            same_text_selected = false;
12397                            selected_text = None;
12398                        }
12399                    }
12400                }
12401            }
12402
12403            if only_carets {
12404                for selection in &mut selections {
12405                    let word_range = movement::surrounding_word(
12406                        &display_map,
12407                        selection.start.to_display_point(&display_map),
12408                    );
12409                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12410                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12411                    selection.goal = SelectionGoal::None;
12412                    selection.reversed = false;
12413                }
12414                if selections.len() == 1 {
12415                    let selection = selections
12416                        .last()
12417                        .expect("ensured that there's only one selection");
12418                    let query = buffer
12419                        .text_for_range(selection.start..selection.end)
12420                        .collect::<String>();
12421                    let is_empty = query.is_empty();
12422                    let select_state = SelectNextState {
12423                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12424                        wordwise: true,
12425                        done: is_empty,
12426                    };
12427                    self.select_prev_state = Some(select_state);
12428                } else {
12429                    self.select_prev_state = None;
12430                }
12431
12432                self.unfold_ranges(
12433                    &selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
12434                    false,
12435                    true,
12436                    cx,
12437                );
12438                self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
12439                    s.select(selections);
12440                });
12441            } else if let Some(selected_text) = selected_text {
12442                self.select_prev_state = Some(SelectNextState {
12443                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12444                    wordwise: false,
12445                    done: false,
12446                });
12447                self.select_previous(action, window, cx)?;
12448            }
12449        }
12450        Ok(())
12451    }
12452
12453    pub fn find_next_match(
12454        &mut self,
12455        _: &FindNextMatch,
12456        window: &mut Window,
12457        cx: &mut Context<Self>,
12458    ) -> Result<()> {
12459        let selections = self.selections.disjoint_anchors();
12460        match selections.first() {
12461            Some(first) if selections.len() >= 2 => {
12462                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12463                    s.select_ranges([first.range()]);
12464                });
12465            }
12466            _ => self.select_next(
12467                &SelectNext {
12468                    replace_newest: true,
12469                },
12470                window,
12471                cx,
12472            )?,
12473        }
12474        Ok(())
12475    }
12476
12477    pub fn find_previous_match(
12478        &mut self,
12479        _: &FindPreviousMatch,
12480        window: &mut Window,
12481        cx: &mut Context<Self>,
12482    ) -> Result<()> {
12483        let selections = self.selections.disjoint_anchors();
12484        match selections.last() {
12485            Some(last) if selections.len() >= 2 => {
12486                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12487                    s.select_ranges([last.range()]);
12488                });
12489            }
12490            _ => self.select_previous(
12491                &SelectPrevious {
12492                    replace_newest: true,
12493                },
12494                window,
12495                cx,
12496            )?,
12497        }
12498        Ok(())
12499    }
12500
12501    pub fn toggle_comments(
12502        &mut self,
12503        action: &ToggleComments,
12504        window: &mut Window,
12505        cx: &mut Context<Self>,
12506    ) {
12507        if self.read_only(cx) {
12508            return;
12509        }
12510        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12511        let text_layout_details = &self.text_layout_details(window);
12512        self.transact(window, cx, |this, window, cx| {
12513            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12514            let mut edits = Vec::new();
12515            let mut selection_edit_ranges = Vec::new();
12516            let mut last_toggled_row = None;
12517            let snapshot = this.buffer.read(cx).read(cx);
12518            let empty_str: Arc<str> = Arc::default();
12519            let mut suffixes_inserted = Vec::new();
12520            let ignore_indent = action.ignore_indent;
12521
12522            fn comment_prefix_range(
12523                snapshot: &MultiBufferSnapshot,
12524                row: MultiBufferRow,
12525                comment_prefix: &str,
12526                comment_prefix_whitespace: &str,
12527                ignore_indent: bool,
12528            ) -> Range<Point> {
12529                let indent_size = if ignore_indent {
12530                    0
12531                } else {
12532                    snapshot.indent_size_for_line(row).len
12533                };
12534
12535                let start = Point::new(row.0, indent_size);
12536
12537                let mut line_bytes = snapshot
12538                    .bytes_in_range(start..snapshot.max_point())
12539                    .flatten()
12540                    .copied();
12541
12542                // If this line currently begins with the line comment prefix, then record
12543                // the range containing the prefix.
12544                if line_bytes
12545                    .by_ref()
12546                    .take(comment_prefix.len())
12547                    .eq(comment_prefix.bytes())
12548                {
12549                    // Include any whitespace that matches the comment prefix.
12550                    let matching_whitespace_len = line_bytes
12551                        .zip(comment_prefix_whitespace.bytes())
12552                        .take_while(|(a, b)| a == b)
12553                        .count() as u32;
12554                    let end = Point::new(
12555                        start.row,
12556                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12557                    );
12558                    start..end
12559                } else {
12560                    start..start
12561                }
12562            }
12563
12564            fn comment_suffix_range(
12565                snapshot: &MultiBufferSnapshot,
12566                row: MultiBufferRow,
12567                comment_suffix: &str,
12568                comment_suffix_has_leading_space: bool,
12569            ) -> Range<Point> {
12570                let end = Point::new(row.0, snapshot.line_len(row));
12571                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12572
12573                let mut line_end_bytes = snapshot
12574                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12575                    .flatten()
12576                    .copied();
12577
12578                let leading_space_len = if suffix_start_column > 0
12579                    && line_end_bytes.next() == Some(b' ')
12580                    && comment_suffix_has_leading_space
12581                {
12582                    1
12583                } else {
12584                    0
12585                };
12586
12587                // If this line currently begins with the line comment prefix, then record
12588                // the range containing the prefix.
12589                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12590                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12591                    start..end
12592                } else {
12593                    end..end
12594                }
12595            }
12596
12597            // TODO: Handle selections that cross excerpts
12598            for selection in &mut selections {
12599                let start_column = snapshot
12600                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12601                    .len;
12602                let language = if let Some(language) =
12603                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12604                {
12605                    language
12606                } else {
12607                    continue;
12608                };
12609
12610                selection_edit_ranges.clear();
12611
12612                // If multiple selections contain a given row, avoid processing that
12613                // row more than once.
12614                let mut start_row = MultiBufferRow(selection.start.row);
12615                if last_toggled_row == Some(start_row) {
12616                    start_row = start_row.next_row();
12617                }
12618                let end_row =
12619                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12620                        MultiBufferRow(selection.end.row - 1)
12621                    } else {
12622                        MultiBufferRow(selection.end.row)
12623                    };
12624                last_toggled_row = Some(end_row);
12625
12626                if start_row > end_row {
12627                    continue;
12628                }
12629
12630                // If the language has line comments, toggle those.
12631                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12632
12633                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12634                if ignore_indent {
12635                    full_comment_prefixes = full_comment_prefixes
12636                        .into_iter()
12637                        .map(|s| Arc::from(s.trim_end()))
12638                        .collect();
12639                }
12640
12641                if !full_comment_prefixes.is_empty() {
12642                    let first_prefix = full_comment_prefixes
12643                        .first()
12644                        .expect("prefixes is non-empty");
12645                    let prefix_trimmed_lengths = full_comment_prefixes
12646                        .iter()
12647                        .map(|p| p.trim_end_matches(' ').len())
12648                        .collect::<SmallVec<[usize; 4]>>();
12649
12650                    let mut all_selection_lines_are_comments = true;
12651
12652                    for row in start_row.0..=end_row.0 {
12653                        let row = MultiBufferRow(row);
12654                        if start_row < end_row && snapshot.is_line_blank(row) {
12655                            continue;
12656                        }
12657
12658                        let prefix_range = full_comment_prefixes
12659                            .iter()
12660                            .zip(prefix_trimmed_lengths.iter().copied())
12661                            .map(|(prefix, trimmed_prefix_len)| {
12662                                comment_prefix_range(
12663                                    snapshot.deref(),
12664                                    row,
12665                                    &prefix[..trimmed_prefix_len],
12666                                    &prefix[trimmed_prefix_len..],
12667                                    ignore_indent,
12668                                )
12669                            })
12670                            .max_by_key(|range| range.end.column - range.start.column)
12671                            .expect("prefixes is non-empty");
12672
12673                        if prefix_range.is_empty() {
12674                            all_selection_lines_are_comments = false;
12675                        }
12676
12677                        selection_edit_ranges.push(prefix_range);
12678                    }
12679
12680                    if all_selection_lines_are_comments {
12681                        edits.extend(
12682                            selection_edit_ranges
12683                                .iter()
12684                                .cloned()
12685                                .map(|range| (range, empty_str.clone())),
12686                        );
12687                    } else {
12688                        let min_column = selection_edit_ranges
12689                            .iter()
12690                            .map(|range| range.start.column)
12691                            .min()
12692                            .unwrap_or(0);
12693                        edits.extend(selection_edit_ranges.iter().map(|range| {
12694                            let position = Point::new(range.start.row, min_column);
12695                            (position..position, first_prefix.clone())
12696                        }));
12697                    }
12698                } else if let Some((full_comment_prefix, comment_suffix)) =
12699                    language.block_comment_delimiters()
12700                {
12701                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
12702                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
12703                    let prefix_range = comment_prefix_range(
12704                        snapshot.deref(),
12705                        start_row,
12706                        comment_prefix,
12707                        comment_prefix_whitespace,
12708                        ignore_indent,
12709                    );
12710                    let suffix_range = comment_suffix_range(
12711                        snapshot.deref(),
12712                        end_row,
12713                        comment_suffix.trim_start_matches(' '),
12714                        comment_suffix.starts_with(' '),
12715                    );
12716
12717                    if prefix_range.is_empty() || suffix_range.is_empty() {
12718                        edits.push((
12719                            prefix_range.start..prefix_range.start,
12720                            full_comment_prefix.clone(),
12721                        ));
12722                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
12723                        suffixes_inserted.push((end_row, comment_suffix.len()));
12724                    } else {
12725                        edits.push((prefix_range, empty_str.clone()));
12726                        edits.push((suffix_range, empty_str.clone()));
12727                    }
12728                } else {
12729                    continue;
12730                }
12731            }
12732
12733            drop(snapshot);
12734            this.buffer.update(cx, |buffer, cx| {
12735                buffer.edit(edits, None, cx);
12736            });
12737
12738            // Adjust selections so that they end before any comment suffixes that
12739            // were inserted.
12740            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
12741            let mut selections = this.selections.all::<Point>(cx);
12742            let snapshot = this.buffer.read(cx).read(cx);
12743            for selection in &mut selections {
12744                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
12745                    match row.cmp(&MultiBufferRow(selection.end.row)) {
12746                        Ordering::Less => {
12747                            suffixes_inserted.next();
12748                            continue;
12749                        }
12750                        Ordering::Greater => break,
12751                        Ordering::Equal => {
12752                            if selection.end.column == snapshot.line_len(row) {
12753                                if selection.is_empty() {
12754                                    selection.start.column -= suffix_len as u32;
12755                                }
12756                                selection.end.column -= suffix_len as u32;
12757                            }
12758                            break;
12759                        }
12760                    }
12761                }
12762            }
12763
12764            drop(snapshot);
12765            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12766                s.select(selections)
12767            });
12768
12769            let selections = this.selections.all::<Point>(cx);
12770            let selections_on_single_row = selections.windows(2).all(|selections| {
12771                selections[0].start.row == selections[1].start.row
12772                    && selections[0].end.row == selections[1].end.row
12773                    && selections[0].start.row == selections[0].end.row
12774            });
12775            let selections_selecting = selections
12776                .iter()
12777                .any(|selection| selection.start != selection.end);
12778            let advance_downwards = action.advance_downwards
12779                && selections_on_single_row
12780                && !selections_selecting
12781                && !matches!(this.mode, EditorMode::SingleLine { .. });
12782
12783            if advance_downwards {
12784                let snapshot = this.buffer.read(cx).snapshot(cx);
12785
12786                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12787                    s.move_cursors_with(|display_snapshot, display_point, _| {
12788                        let mut point = display_point.to_point(display_snapshot);
12789                        point.row += 1;
12790                        point = snapshot.clip_point(point, Bias::Left);
12791                        let display_point = point.to_display_point(display_snapshot);
12792                        let goal = SelectionGoal::HorizontalPosition(
12793                            display_snapshot
12794                                .x_for_display_point(display_point, text_layout_details)
12795                                .into(),
12796                        );
12797                        (display_point, goal)
12798                    })
12799                });
12800            }
12801        });
12802    }
12803
12804    pub fn select_enclosing_symbol(
12805        &mut self,
12806        _: &SelectEnclosingSymbol,
12807        window: &mut Window,
12808        cx: &mut Context<Self>,
12809    ) {
12810        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12811
12812        let buffer = self.buffer.read(cx).snapshot(cx);
12813        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
12814
12815        fn update_selection(
12816            selection: &Selection<usize>,
12817            buffer_snap: &MultiBufferSnapshot,
12818        ) -> Option<Selection<usize>> {
12819            let cursor = selection.head();
12820            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
12821            for symbol in symbols.iter().rev() {
12822                let start = symbol.range.start.to_offset(buffer_snap);
12823                let end = symbol.range.end.to_offset(buffer_snap);
12824                let new_range = start..end;
12825                if start < selection.start || end > selection.end {
12826                    return Some(Selection {
12827                        id: selection.id,
12828                        start: new_range.start,
12829                        end: new_range.end,
12830                        goal: SelectionGoal::None,
12831                        reversed: selection.reversed,
12832                    });
12833                }
12834            }
12835            None
12836        }
12837
12838        let mut selected_larger_symbol = false;
12839        let new_selections = old_selections
12840            .iter()
12841            .map(|selection| match update_selection(selection, &buffer) {
12842                Some(new_selection) => {
12843                    if new_selection.range() != selection.range() {
12844                        selected_larger_symbol = true;
12845                    }
12846                    new_selection
12847                }
12848                None => selection.clone(),
12849            })
12850            .collect::<Vec<_>>();
12851
12852        if selected_larger_symbol {
12853            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12854                s.select(new_selections);
12855            });
12856        }
12857    }
12858
12859    pub fn select_larger_syntax_node(
12860        &mut self,
12861        _: &SelectLargerSyntaxNode,
12862        window: &mut Window,
12863        cx: &mut Context<Self>,
12864    ) {
12865        let Some(visible_row_count) = self.visible_row_count() else {
12866            return;
12867        };
12868        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
12869        if old_selections.is_empty() {
12870            return;
12871        }
12872
12873        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12874
12875        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12876        let buffer = self.buffer.read(cx).snapshot(cx);
12877
12878        let mut selected_larger_node = false;
12879        let mut new_selections = old_selections
12880            .iter()
12881            .map(|selection| {
12882                let old_range = selection.start..selection.end;
12883
12884                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
12885                    // manually select word at selection
12886                    if ["string_content", "inline"].contains(&node.kind()) {
12887                        let word_range = {
12888                            let display_point = buffer
12889                                .offset_to_point(old_range.start)
12890                                .to_display_point(&display_map);
12891                            let Range { start, end } =
12892                                movement::surrounding_word(&display_map, display_point);
12893                            start.to_point(&display_map).to_offset(&buffer)
12894                                ..end.to_point(&display_map).to_offset(&buffer)
12895                        };
12896                        // ignore if word is already selected
12897                        if !word_range.is_empty() && old_range != word_range {
12898                            let last_word_range = {
12899                                let display_point = buffer
12900                                    .offset_to_point(old_range.end)
12901                                    .to_display_point(&display_map);
12902                                let Range { start, end } =
12903                                    movement::surrounding_word(&display_map, display_point);
12904                                start.to_point(&display_map).to_offset(&buffer)
12905                                    ..end.to_point(&display_map).to_offset(&buffer)
12906                            };
12907                            // only select word if start and end point belongs to same word
12908                            if word_range == last_word_range {
12909                                selected_larger_node = true;
12910                                return Selection {
12911                                    id: selection.id,
12912                                    start: word_range.start,
12913                                    end: word_range.end,
12914                                    goal: SelectionGoal::None,
12915                                    reversed: selection.reversed,
12916                                };
12917                            }
12918                        }
12919                    }
12920                }
12921
12922                let mut new_range = old_range.clone();
12923                let mut new_node = None;
12924                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
12925                {
12926                    new_node = Some(node);
12927                    new_range = match containing_range {
12928                        MultiOrSingleBufferOffsetRange::Single(_) => break,
12929                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
12930                    };
12931                    if !display_map.intersects_fold(new_range.start)
12932                        && !display_map.intersects_fold(new_range.end)
12933                    {
12934                        break;
12935                    }
12936                }
12937
12938                if let Some(node) = new_node {
12939                    // Log the ancestor, to support using this action as a way to explore TreeSitter
12940                    // nodes. Parent and grandparent are also logged because this operation will not
12941                    // visit nodes that have the same range as their parent.
12942                    log::info!("Node: {node:?}");
12943                    let parent = node.parent();
12944                    log::info!("Parent: {parent:?}");
12945                    let grandparent = parent.and_then(|x| x.parent());
12946                    log::info!("Grandparent: {grandparent:?}");
12947                }
12948
12949                selected_larger_node |= new_range != old_range;
12950                Selection {
12951                    id: selection.id,
12952                    start: new_range.start,
12953                    end: new_range.end,
12954                    goal: SelectionGoal::None,
12955                    reversed: selection.reversed,
12956                }
12957            })
12958            .collect::<Vec<_>>();
12959
12960        if !selected_larger_node {
12961            return; // don't put this call in the history
12962        }
12963
12964        // scroll based on transformation done to the last selection created by the user
12965        let (last_old, last_new) = old_selections
12966            .last()
12967            .zip(new_selections.last().cloned())
12968            .expect("old_selections isn't empty");
12969
12970        // revert selection
12971        let is_selection_reversed = {
12972            let should_newest_selection_be_reversed = last_old.start != last_new.start;
12973            new_selections.last_mut().expect("checked above").reversed =
12974                should_newest_selection_be_reversed;
12975            should_newest_selection_be_reversed
12976        };
12977
12978        if selected_larger_node {
12979            self.select_syntax_node_history.disable_clearing = true;
12980            self.change_selections(None, window, cx, |s| {
12981                s.select(new_selections.clone());
12982            });
12983            self.select_syntax_node_history.disable_clearing = false;
12984        }
12985
12986        let start_row = last_new.start.to_display_point(&display_map).row().0;
12987        let end_row = last_new.end.to_display_point(&display_map).row().0;
12988        let selection_height = end_row - start_row + 1;
12989        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
12990
12991        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
12992        let scroll_behavior = if fits_on_the_screen {
12993            self.request_autoscroll(Autoscroll::fit(), cx);
12994            SelectSyntaxNodeScrollBehavior::FitSelection
12995        } else if is_selection_reversed {
12996            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
12997            SelectSyntaxNodeScrollBehavior::CursorTop
12998        } else {
12999            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13000            SelectSyntaxNodeScrollBehavior::CursorBottom
13001        };
13002
13003        self.select_syntax_node_history.push((
13004            old_selections,
13005            scroll_behavior,
13006            is_selection_reversed,
13007        ));
13008    }
13009
13010    pub fn select_smaller_syntax_node(
13011        &mut self,
13012        _: &SelectSmallerSyntaxNode,
13013        window: &mut Window,
13014        cx: &mut Context<Self>,
13015    ) {
13016        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13017
13018        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13019            self.select_syntax_node_history.pop()
13020        {
13021            if let Some(selection) = selections.last_mut() {
13022                selection.reversed = is_selection_reversed;
13023            }
13024
13025            self.select_syntax_node_history.disable_clearing = true;
13026            self.change_selections(None, window, cx, |s| {
13027                s.select(selections.to_vec());
13028            });
13029            self.select_syntax_node_history.disable_clearing = false;
13030
13031            match scroll_behavior {
13032                SelectSyntaxNodeScrollBehavior::CursorTop => {
13033                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13034                }
13035                SelectSyntaxNodeScrollBehavior::FitSelection => {
13036                    self.request_autoscroll(Autoscroll::fit(), cx);
13037                }
13038                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13039                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13040                }
13041            }
13042        }
13043    }
13044
13045    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13046        if !EditorSettings::get_global(cx).gutter.runnables {
13047            self.clear_tasks();
13048            return Task::ready(());
13049        }
13050        let project = self.project.as_ref().map(Entity::downgrade);
13051        let task_sources = self.lsp_task_sources(cx);
13052        cx.spawn_in(window, async move |editor, cx| {
13053            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13054            let Some(project) = project.and_then(|p| p.upgrade()) else {
13055                return;
13056            };
13057            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13058                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13059            }) else {
13060                return;
13061            };
13062
13063            let hide_runnables = project
13064                .update(cx, |project, cx| {
13065                    // Do not display any test indicators in non-dev server remote projects.
13066                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13067                })
13068                .unwrap_or(true);
13069            if hide_runnables {
13070                return;
13071            }
13072            let new_rows =
13073                cx.background_spawn({
13074                    let snapshot = display_snapshot.clone();
13075                    async move {
13076                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13077                    }
13078                })
13079                    .await;
13080            let Ok(lsp_tasks) =
13081                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13082            else {
13083                return;
13084            };
13085            let lsp_tasks = lsp_tasks.await;
13086
13087            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13088                lsp_tasks
13089                    .into_iter()
13090                    .flat_map(|(kind, tasks)| {
13091                        tasks.into_iter().filter_map(move |(location, task)| {
13092                            Some((kind.clone(), location?, task))
13093                        })
13094                    })
13095                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13096                        let buffer = location.target.buffer;
13097                        let buffer_snapshot = buffer.read(cx).snapshot();
13098                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13099                            |(excerpt_id, snapshot, _)| {
13100                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13101                                    display_snapshot
13102                                        .buffer_snapshot
13103                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13104                                } else {
13105                                    None
13106                                }
13107                            },
13108                        );
13109                        if let Some(offset) = offset {
13110                            let task_buffer_range =
13111                                location.target.range.to_point(&buffer_snapshot);
13112                            let context_buffer_range =
13113                                task_buffer_range.to_offset(&buffer_snapshot);
13114                            let context_range = BufferOffset(context_buffer_range.start)
13115                                ..BufferOffset(context_buffer_range.end);
13116
13117                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13118                                .or_insert_with(|| RunnableTasks {
13119                                    templates: Vec::new(),
13120                                    offset,
13121                                    column: task_buffer_range.start.column,
13122                                    extra_variables: HashMap::default(),
13123                                    context_range,
13124                                })
13125                                .templates
13126                                .push((kind, task.original_task().clone()));
13127                        }
13128
13129                        acc
13130                    })
13131            }) else {
13132                return;
13133            };
13134
13135            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13136            editor
13137                .update(cx, |editor, _| {
13138                    editor.clear_tasks();
13139                    for (key, mut value) in rows {
13140                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13141                            value.templates.extend(lsp_tasks.templates);
13142                        }
13143
13144                        editor.insert_tasks(key, value);
13145                    }
13146                    for (key, value) in lsp_tasks_by_rows {
13147                        editor.insert_tasks(key, value);
13148                    }
13149                })
13150                .ok();
13151        })
13152    }
13153    fn fetch_runnable_ranges(
13154        snapshot: &DisplaySnapshot,
13155        range: Range<Anchor>,
13156    ) -> Vec<language::RunnableRange> {
13157        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13158    }
13159
13160    fn runnable_rows(
13161        project: Entity<Project>,
13162        snapshot: DisplaySnapshot,
13163        runnable_ranges: Vec<RunnableRange>,
13164        mut cx: AsyncWindowContext,
13165    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13166        runnable_ranges
13167            .into_iter()
13168            .filter_map(|mut runnable| {
13169                let tasks = cx
13170                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13171                    .ok()?;
13172                if tasks.is_empty() {
13173                    return None;
13174                }
13175
13176                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13177
13178                let row = snapshot
13179                    .buffer_snapshot
13180                    .buffer_line_for_row(MultiBufferRow(point.row))?
13181                    .1
13182                    .start
13183                    .row;
13184
13185                let context_range =
13186                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13187                Some((
13188                    (runnable.buffer_id, row),
13189                    RunnableTasks {
13190                        templates: tasks,
13191                        offset: snapshot
13192                            .buffer_snapshot
13193                            .anchor_before(runnable.run_range.start),
13194                        context_range,
13195                        column: point.column,
13196                        extra_variables: runnable.extra_captures,
13197                    },
13198                ))
13199            })
13200            .collect()
13201    }
13202
13203    fn templates_with_tags(
13204        project: &Entity<Project>,
13205        runnable: &mut Runnable,
13206        cx: &mut App,
13207    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13208        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13209            let (worktree_id, file) = project
13210                .buffer_for_id(runnable.buffer, cx)
13211                .and_then(|buffer| buffer.read(cx).file())
13212                .map(|file| (file.worktree_id(cx), file.clone()))
13213                .unzip();
13214
13215            (
13216                project.task_store().read(cx).task_inventory().cloned(),
13217                worktree_id,
13218                file,
13219            )
13220        });
13221
13222        let mut templates_with_tags = mem::take(&mut runnable.tags)
13223            .into_iter()
13224            .flat_map(|RunnableTag(tag)| {
13225                inventory
13226                    .as_ref()
13227                    .into_iter()
13228                    .flat_map(|inventory| {
13229                        inventory.read(cx).list_tasks(
13230                            file.clone(),
13231                            Some(runnable.language.clone()),
13232                            worktree_id,
13233                            cx,
13234                        )
13235                    })
13236                    .filter(move |(_, template)| {
13237                        template.tags.iter().any(|source_tag| source_tag == &tag)
13238                    })
13239            })
13240            .sorted_by_key(|(kind, _)| kind.to_owned())
13241            .collect::<Vec<_>>();
13242        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13243            // Strongest source wins; if we have worktree tag binding, prefer that to
13244            // global and language bindings;
13245            // if we have a global binding, prefer that to language binding.
13246            let first_mismatch = templates_with_tags
13247                .iter()
13248                .position(|(tag_source, _)| tag_source != leading_tag_source);
13249            if let Some(index) = first_mismatch {
13250                templates_with_tags.truncate(index);
13251            }
13252        }
13253
13254        templates_with_tags
13255    }
13256
13257    pub fn move_to_enclosing_bracket(
13258        &mut self,
13259        _: &MoveToEnclosingBracket,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13264        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13265            s.move_offsets_with(|snapshot, selection| {
13266                let Some(enclosing_bracket_ranges) =
13267                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13268                else {
13269                    return;
13270                };
13271
13272                let mut best_length = usize::MAX;
13273                let mut best_inside = false;
13274                let mut best_in_bracket_range = false;
13275                let mut best_destination = None;
13276                for (open, close) in enclosing_bracket_ranges {
13277                    let close = close.to_inclusive();
13278                    let length = close.end() - open.start;
13279                    let inside = selection.start >= open.end && selection.end <= *close.start();
13280                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13281                        || close.contains(&selection.head());
13282
13283                    // If best is next to a bracket and current isn't, skip
13284                    if !in_bracket_range && best_in_bracket_range {
13285                        continue;
13286                    }
13287
13288                    // Prefer smaller lengths unless best is inside and current isn't
13289                    if length > best_length && (best_inside || !inside) {
13290                        continue;
13291                    }
13292
13293                    best_length = length;
13294                    best_inside = inside;
13295                    best_in_bracket_range = in_bracket_range;
13296                    best_destination = Some(
13297                        if close.contains(&selection.start) && close.contains(&selection.end) {
13298                            if inside { open.end } else { open.start }
13299                        } else if inside {
13300                            *close.start()
13301                        } else {
13302                            *close.end()
13303                        },
13304                    );
13305                }
13306
13307                if let Some(destination) = best_destination {
13308                    selection.collapse_to(destination, SelectionGoal::None);
13309                }
13310            })
13311        });
13312    }
13313
13314    pub fn undo_selection(
13315        &mut self,
13316        _: &UndoSelection,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13321        self.end_selection(window, cx);
13322        self.selection_history.mode = SelectionHistoryMode::Undoing;
13323        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13324            self.change_selections(None, window, cx, |s| {
13325                s.select_anchors(entry.selections.to_vec())
13326            });
13327            self.select_next_state = entry.select_next_state;
13328            self.select_prev_state = entry.select_prev_state;
13329            self.add_selections_state = entry.add_selections_state;
13330            self.request_autoscroll(Autoscroll::newest(), cx);
13331        }
13332        self.selection_history.mode = SelectionHistoryMode::Normal;
13333    }
13334
13335    pub fn redo_selection(
13336        &mut self,
13337        _: &RedoSelection,
13338        window: &mut Window,
13339        cx: &mut Context<Self>,
13340    ) {
13341        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13342        self.end_selection(window, cx);
13343        self.selection_history.mode = SelectionHistoryMode::Redoing;
13344        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13345            self.change_selections(None, window, cx, |s| {
13346                s.select_anchors(entry.selections.to_vec())
13347            });
13348            self.select_next_state = entry.select_next_state;
13349            self.select_prev_state = entry.select_prev_state;
13350            self.add_selections_state = entry.add_selections_state;
13351            self.request_autoscroll(Autoscroll::newest(), cx);
13352        }
13353        self.selection_history.mode = SelectionHistoryMode::Normal;
13354    }
13355
13356    pub fn expand_excerpts(
13357        &mut self,
13358        action: &ExpandExcerpts,
13359        _: &mut Window,
13360        cx: &mut Context<Self>,
13361    ) {
13362        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13363    }
13364
13365    pub fn expand_excerpts_down(
13366        &mut self,
13367        action: &ExpandExcerptsDown,
13368        _: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) {
13371        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13372    }
13373
13374    pub fn expand_excerpts_up(
13375        &mut self,
13376        action: &ExpandExcerptsUp,
13377        _: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13381    }
13382
13383    pub fn expand_excerpts_for_direction(
13384        &mut self,
13385        lines: u32,
13386        direction: ExpandExcerptDirection,
13387
13388        cx: &mut Context<Self>,
13389    ) {
13390        let selections = self.selections.disjoint_anchors();
13391
13392        let lines = if lines == 0 {
13393            EditorSettings::get_global(cx).expand_excerpt_lines
13394        } else {
13395            lines
13396        };
13397
13398        self.buffer.update(cx, |buffer, cx| {
13399            let snapshot = buffer.snapshot(cx);
13400            let mut excerpt_ids = selections
13401                .iter()
13402                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13403                .collect::<Vec<_>>();
13404            excerpt_ids.sort();
13405            excerpt_ids.dedup();
13406            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13407        })
13408    }
13409
13410    pub fn expand_excerpt(
13411        &mut self,
13412        excerpt: ExcerptId,
13413        direction: ExpandExcerptDirection,
13414        window: &mut Window,
13415        cx: &mut Context<Self>,
13416    ) {
13417        let current_scroll_position = self.scroll_position(cx);
13418        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13419        let mut should_scroll_up = false;
13420
13421        if direction == ExpandExcerptDirection::Down {
13422            let multi_buffer = self.buffer.read(cx);
13423            let snapshot = multi_buffer.snapshot(cx);
13424            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13425                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13426                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13427                        let buffer_snapshot = buffer.read(cx).snapshot();
13428                        let excerpt_end_row =
13429                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13430                        let last_row = buffer_snapshot.max_point().row;
13431                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13432                        should_scroll_up = lines_below >= lines_to_expand;
13433                    }
13434                }
13435            }
13436        }
13437
13438        self.buffer.update(cx, |buffer, cx| {
13439            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13440        });
13441
13442        if should_scroll_up {
13443            let new_scroll_position =
13444                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13445            self.set_scroll_position(new_scroll_position, window, cx);
13446        }
13447    }
13448
13449    pub fn go_to_singleton_buffer_point(
13450        &mut self,
13451        point: Point,
13452        window: &mut Window,
13453        cx: &mut Context<Self>,
13454    ) {
13455        self.go_to_singleton_buffer_range(point..point, window, cx);
13456    }
13457
13458    pub fn go_to_singleton_buffer_range(
13459        &mut self,
13460        range: Range<Point>,
13461        window: &mut Window,
13462        cx: &mut Context<Self>,
13463    ) {
13464        let multibuffer = self.buffer().read(cx);
13465        let Some(buffer) = multibuffer.as_singleton() else {
13466            return;
13467        };
13468        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13469            return;
13470        };
13471        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13472            return;
13473        };
13474        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13475            s.select_anchor_ranges([start..end])
13476        });
13477    }
13478
13479    pub fn go_to_diagnostic(
13480        &mut self,
13481        _: &GoToDiagnostic,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13486        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13487    }
13488
13489    pub fn go_to_prev_diagnostic(
13490        &mut self,
13491        _: &GoToPreviousDiagnostic,
13492        window: &mut Window,
13493        cx: &mut Context<Self>,
13494    ) {
13495        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13496        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13497    }
13498
13499    pub fn go_to_diagnostic_impl(
13500        &mut self,
13501        direction: Direction,
13502        window: &mut Window,
13503        cx: &mut Context<Self>,
13504    ) {
13505        let buffer = self.buffer.read(cx).snapshot(cx);
13506        let selection = self.selections.newest::<usize>(cx);
13507
13508        let mut active_group_id = None;
13509        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13510            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13511                active_group_id = Some(active_group.group_id);
13512            }
13513        }
13514
13515        fn filtered(
13516            snapshot: EditorSnapshot,
13517            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13518        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13519            diagnostics
13520                .filter(|entry| entry.range.start != entry.range.end)
13521                .filter(|entry| !entry.diagnostic.is_unnecessary)
13522                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13523        }
13524
13525        let snapshot = self.snapshot(window, cx);
13526        let before = filtered(
13527            snapshot.clone(),
13528            buffer
13529                .diagnostics_in_range(0..selection.start)
13530                .filter(|entry| entry.range.start <= selection.start),
13531        );
13532        let after = filtered(
13533            snapshot,
13534            buffer
13535                .diagnostics_in_range(selection.start..buffer.len())
13536                .filter(|entry| entry.range.start >= selection.start),
13537        );
13538
13539        let mut found: Option<DiagnosticEntry<usize>> = None;
13540        if direction == Direction::Prev {
13541            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13542            {
13543                for diagnostic in prev_diagnostics.into_iter().rev() {
13544                    if diagnostic.range.start != selection.start
13545                        || active_group_id
13546                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13547                    {
13548                        found = Some(diagnostic);
13549                        break 'outer;
13550                    }
13551                }
13552            }
13553        } else {
13554            for diagnostic in after.chain(before) {
13555                if diagnostic.range.start != selection.start
13556                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13557                {
13558                    found = Some(diagnostic);
13559                    break;
13560                }
13561            }
13562        }
13563        let Some(next_diagnostic) = found else {
13564            return;
13565        };
13566
13567        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13568            return;
13569        };
13570        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13571            s.select_ranges(vec![
13572                next_diagnostic.range.start..next_diagnostic.range.start,
13573            ])
13574        });
13575        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13576        self.refresh_inline_completion(false, true, window, cx);
13577    }
13578
13579    fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13580        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13581        let snapshot = self.snapshot(window, cx);
13582        let selection = self.selections.newest::<Point>(cx);
13583        self.go_to_hunk_before_or_after_position(
13584            &snapshot,
13585            selection.head(),
13586            Direction::Next,
13587            window,
13588            cx,
13589        );
13590    }
13591
13592    pub fn go_to_hunk_before_or_after_position(
13593        &mut self,
13594        snapshot: &EditorSnapshot,
13595        position: Point,
13596        direction: Direction,
13597        window: &mut Window,
13598        cx: &mut Context<Editor>,
13599    ) {
13600        let row = if direction == Direction::Next {
13601            self.hunk_after_position(snapshot, position)
13602                .map(|hunk| hunk.row_range.start)
13603        } else {
13604            self.hunk_before_position(snapshot, position)
13605        };
13606
13607        if let Some(row) = row {
13608            let destination = Point::new(row.0, 0);
13609            let autoscroll = Autoscroll::center();
13610
13611            self.unfold_ranges(&[destination..destination], false, false, cx);
13612            self.change_selections(Some(autoscroll), window, cx, |s| {
13613                s.select_ranges([destination..destination]);
13614            });
13615        }
13616    }
13617
13618    fn hunk_after_position(
13619        &mut self,
13620        snapshot: &EditorSnapshot,
13621        position: Point,
13622    ) -> Option<MultiBufferDiffHunk> {
13623        snapshot
13624            .buffer_snapshot
13625            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13626            .find(|hunk| hunk.row_range.start.0 > position.row)
13627            .or_else(|| {
13628                snapshot
13629                    .buffer_snapshot
13630                    .diff_hunks_in_range(Point::zero()..position)
13631                    .find(|hunk| hunk.row_range.end.0 < position.row)
13632            })
13633    }
13634
13635    fn go_to_prev_hunk(
13636        &mut self,
13637        _: &GoToPreviousHunk,
13638        window: &mut Window,
13639        cx: &mut Context<Self>,
13640    ) {
13641        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13642        let snapshot = self.snapshot(window, cx);
13643        let selection = self.selections.newest::<Point>(cx);
13644        self.go_to_hunk_before_or_after_position(
13645            &snapshot,
13646            selection.head(),
13647            Direction::Prev,
13648            window,
13649            cx,
13650        );
13651    }
13652
13653    fn hunk_before_position(
13654        &mut self,
13655        snapshot: &EditorSnapshot,
13656        position: Point,
13657    ) -> Option<MultiBufferRow> {
13658        snapshot
13659            .buffer_snapshot
13660            .diff_hunk_before(position)
13661            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13662    }
13663
13664    fn go_to_next_change(
13665        &mut self,
13666        _: &GoToNextChange,
13667        window: &mut Window,
13668        cx: &mut Context<Self>,
13669    ) {
13670        if let Some(selections) = self
13671            .change_list
13672            .next_change(1, Direction::Next)
13673            .map(|s| s.to_vec())
13674        {
13675            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13676                let map = s.display_map();
13677                s.select_display_ranges(selections.iter().map(|a| {
13678                    let point = a.to_display_point(&map);
13679                    point..point
13680                }))
13681            })
13682        }
13683    }
13684
13685    fn go_to_previous_change(
13686        &mut self,
13687        _: &GoToPreviousChange,
13688        window: &mut Window,
13689        cx: &mut Context<Self>,
13690    ) {
13691        if let Some(selections) = self
13692            .change_list
13693            .next_change(1, Direction::Prev)
13694            .map(|s| s.to_vec())
13695        {
13696            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13697                let map = s.display_map();
13698                s.select_display_ranges(selections.iter().map(|a| {
13699                    let point = a.to_display_point(&map);
13700                    point..point
13701                }))
13702            })
13703        }
13704    }
13705
13706    fn go_to_line<T: 'static>(
13707        &mut self,
13708        position: Anchor,
13709        highlight_color: Option<Hsla>,
13710        window: &mut Window,
13711        cx: &mut Context<Self>,
13712    ) {
13713        let snapshot = self.snapshot(window, cx).display_snapshot;
13714        let position = position.to_point(&snapshot.buffer_snapshot);
13715        let start = snapshot
13716            .buffer_snapshot
13717            .clip_point(Point::new(position.row, 0), Bias::Left);
13718        let end = start + Point::new(1, 0);
13719        let start = snapshot.buffer_snapshot.anchor_before(start);
13720        let end = snapshot.buffer_snapshot.anchor_before(end);
13721
13722        self.highlight_rows::<T>(
13723            start..end,
13724            highlight_color
13725                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
13726            Default::default(),
13727            cx,
13728        );
13729        self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
13730    }
13731
13732    pub fn go_to_definition(
13733        &mut self,
13734        _: &GoToDefinition,
13735        window: &mut Window,
13736        cx: &mut Context<Self>,
13737    ) -> Task<Result<Navigated>> {
13738        let definition =
13739            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
13740        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
13741        cx.spawn_in(window, async move |editor, cx| {
13742            if definition.await? == Navigated::Yes {
13743                return Ok(Navigated::Yes);
13744            }
13745            match fallback_strategy {
13746                GoToDefinitionFallback::None => Ok(Navigated::No),
13747                GoToDefinitionFallback::FindAllReferences => {
13748                    match editor.update_in(cx, |editor, window, cx| {
13749                        editor.find_all_references(&FindAllReferences, window, cx)
13750                    })? {
13751                        Some(references) => references.await,
13752                        None => Ok(Navigated::No),
13753                    }
13754                }
13755            }
13756        })
13757    }
13758
13759    pub fn go_to_declaration(
13760        &mut self,
13761        _: &GoToDeclaration,
13762        window: &mut Window,
13763        cx: &mut Context<Self>,
13764    ) -> Task<Result<Navigated>> {
13765        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
13766    }
13767
13768    pub fn go_to_declaration_split(
13769        &mut self,
13770        _: &GoToDeclaration,
13771        window: &mut Window,
13772        cx: &mut Context<Self>,
13773    ) -> Task<Result<Navigated>> {
13774        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
13775    }
13776
13777    pub fn go_to_implementation(
13778        &mut self,
13779        _: &GoToImplementation,
13780        window: &mut Window,
13781        cx: &mut Context<Self>,
13782    ) -> Task<Result<Navigated>> {
13783        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
13784    }
13785
13786    pub fn go_to_implementation_split(
13787        &mut self,
13788        _: &GoToImplementationSplit,
13789        window: &mut Window,
13790        cx: &mut Context<Self>,
13791    ) -> Task<Result<Navigated>> {
13792        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
13793    }
13794
13795    pub fn go_to_type_definition(
13796        &mut self,
13797        _: &GoToTypeDefinition,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) -> Task<Result<Navigated>> {
13801        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
13802    }
13803
13804    pub fn go_to_definition_split(
13805        &mut self,
13806        _: &GoToDefinitionSplit,
13807        window: &mut Window,
13808        cx: &mut Context<Self>,
13809    ) -> Task<Result<Navigated>> {
13810        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
13811    }
13812
13813    pub fn go_to_type_definition_split(
13814        &mut self,
13815        _: &GoToTypeDefinitionSplit,
13816        window: &mut Window,
13817        cx: &mut Context<Self>,
13818    ) -> Task<Result<Navigated>> {
13819        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
13820    }
13821
13822    fn go_to_definition_of_kind(
13823        &mut self,
13824        kind: GotoDefinitionKind,
13825        split: bool,
13826        window: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) -> Task<Result<Navigated>> {
13829        let Some(provider) = self.semantics_provider.clone() else {
13830            return Task::ready(Ok(Navigated::No));
13831        };
13832        let head = self.selections.newest::<usize>(cx).head();
13833        let buffer = self.buffer.read(cx);
13834        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
13835            text_anchor
13836        } else {
13837            return Task::ready(Ok(Navigated::No));
13838        };
13839
13840        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
13841            return Task::ready(Ok(Navigated::No));
13842        };
13843
13844        cx.spawn_in(window, async move |editor, cx| {
13845            let definitions = definitions.await?;
13846            let navigated = editor
13847                .update_in(cx, |editor, window, cx| {
13848                    editor.navigate_to_hover_links(
13849                        Some(kind),
13850                        definitions
13851                            .into_iter()
13852                            .filter(|location| {
13853                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
13854                            })
13855                            .map(HoverLink::Text)
13856                            .collect::<Vec<_>>(),
13857                        split,
13858                        window,
13859                        cx,
13860                    )
13861                })?
13862                .await?;
13863            anyhow::Ok(navigated)
13864        })
13865    }
13866
13867    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
13868        let selection = self.selections.newest_anchor();
13869        let head = selection.head();
13870        let tail = selection.tail();
13871
13872        let Some((buffer, start_position)) =
13873            self.buffer.read(cx).text_anchor_for_position(head, cx)
13874        else {
13875            return;
13876        };
13877
13878        let end_position = if head != tail {
13879            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
13880                return;
13881            };
13882            Some(pos)
13883        } else {
13884            None
13885        };
13886
13887        let url_finder = cx.spawn_in(window, async move |editor, cx| {
13888            let url = if let Some(end_pos) = end_position {
13889                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
13890            } else {
13891                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
13892            };
13893
13894            if let Some(url) = url {
13895                editor.update(cx, |_, cx| {
13896                    cx.open_url(&url);
13897                })
13898            } else {
13899                Ok(())
13900            }
13901        });
13902
13903        url_finder.detach();
13904    }
13905
13906    pub fn open_selected_filename(
13907        &mut self,
13908        _: &OpenSelectedFilename,
13909        window: &mut Window,
13910        cx: &mut Context<Self>,
13911    ) {
13912        let Some(workspace) = self.workspace() else {
13913            return;
13914        };
13915
13916        let position = self.selections.newest_anchor().head();
13917
13918        let Some((buffer, buffer_position)) =
13919            self.buffer.read(cx).text_anchor_for_position(position, cx)
13920        else {
13921            return;
13922        };
13923
13924        let project = self.project.clone();
13925
13926        cx.spawn_in(window, async move |_, cx| {
13927            let result = find_file(&buffer, project, buffer_position, cx).await;
13928
13929            if let Some((_, path)) = result {
13930                workspace
13931                    .update_in(cx, |workspace, window, cx| {
13932                        workspace.open_resolved_path(path, window, cx)
13933                    })?
13934                    .await?;
13935            }
13936            anyhow::Ok(())
13937        })
13938        .detach();
13939    }
13940
13941    pub(crate) fn navigate_to_hover_links(
13942        &mut self,
13943        kind: Option<GotoDefinitionKind>,
13944        mut definitions: Vec<HoverLink>,
13945        split: bool,
13946        window: &mut Window,
13947        cx: &mut Context<Editor>,
13948    ) -> Task<Result<Navigated>> {
13949        // If there is one definition, just open it directly
13950        if definitions.len() == 1 {
13951            let definition = definitions.pop().unwrap();
13952
13953            enum TargetTaskResult {
13954                Location(Option<Location>),
13955                AlreadyNavigated,
13956            }
13957
13958            let target_task = match definition {
13959                HoverLink::Text(link) => {
13960                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
13961                }
13962                HoverLink::InlayHint(lsp_location, server_id) => {
13963                    let computation =
13964                        self.compute_target_location(lsp_location, server_id, window, cx);
13965                    cx.background_spawn(async move {
13966                        let location = computation.await?;
13967                        Ok(TargetTaskResult::Location(location))
13968                    })
13969                }
13970                HoverLink::Url(url) => {
13971                    cx.open_url(&url);
13972                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
13973                }
13974                HoverLink::File(path) => {
13975                    if let Some(workspace) = self.workspace() {
13976                        cx.spawn_in(window, async move |_, cx| {
13977                            workspace
13978                                .update_in(cx, |workspace, window, cx| {
13979                                    workspace.open_resolved_path(path, window, cx)
13980                                })?
13981                                .await
13982                                .map(|_| TargetTaskResult::AlreadyNavigated)
13983                        })
13984                    } else {
13985                        Task::ready(Ok(TargetTaskResult::Location(None)))
13986                    }
13987                }
13988            };
13989            cx.spawn_in(window, async move |editor, cx| {
13990                let target = match target_task.await.context("target resolution task")? {
13991                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
13992                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
13993                    TargetTaskResult::Location(Some(target)) => target,
13994                };
13995
13996                editor.update_in(cx, |editor, window, cx| {
13997                    let Some(workspace) = editor.workspace() else {
13998                        return Navigated::No;
13999                    };
14000                    let pane = workspace.read(cx).active_pane().clone();
14001
14002                    let range = target.range.to_point(target.buffer.read(cx));
14003                    let range = editor.range_for_match(&range);
14004                    let range = collapse_multiline_range(range);
14005
14006                    if !split
14007                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14008                    {
14009                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14010                    } else {
14011                        window.defer(cx, move |window, cx| {
14012                            let target_editor: Entity<Self> =
14013                                workspace.update(cx, |workspace, cx| {
14014                                    let pane = if split {
14015                                        workspace.adjacent_pane(window, cx)
14016                                    } else {
14017                                        workspace.active_pane().clone()
14018                                    };
14019
14020                                    workspace.open_project_item(
14021                                        pane,
14022                                        target.buffer.clone(),
14023                                        true,
14024                                        true,
14025                                        window,
14026                                        cx,
14027                                    )
14028                                });
14029                            target_editor.update(cx, |target_editor, cx| {
14030                                // When selecting a definition in a different buffer, disable the nav history
14031                                // to avoid creating a history entry at the previous cursor location.
14032                                pane.update(cx, |pane, _| pane.disable_history());
14033                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14034                                pane.update(cx, |pane, _| pane.enable_history());
14035                            });
14036                        });
14037                    }
14038                    Navigated::Yes
14039                })
14040            })
14041        } else if !definitions.is_empty() {
14042            cx.spawn_in(window, async move |editor, cx| {
14043                let (title, location_tasks, workspace) = editor
14044                    .update_in(cx, |editor, window, cx| {
14045                        let tab_kind = match kind {
14046                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14047                            _ => "Definitions",
14048                        };
14049                        let title = definitions
14050                            .iter()
14051                            .find_map(|definition| match definition {
14052                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14053                                    let buffer = origin.buffer.read(cx);
14054                                    format!(
14055                                        "{} for {}",
14056                                        tab_kind,
14057                                        buffer
14058                                            .text_for_range(origin.range.clone())
14059                                            .collect::<String>()
14060                                    )
14061                                }),
14062                                HoverLink::InlayHint(_, _) => None,
14063                                HoverLink::Url(_) => None,
14064                                HoverLink::File(_) => None,
14065                            })
14066                            .unwrap_or(tab_kind.to_string());
14067                        let location_tasks = definitions
14068                            .into_iter()
14069                            .map(|definition| match definition {
14070                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14071                                HoverLink::InlayHint(lsp_location, server_id) => editor
14072                                    .compute_target_location(lsp_location, server_id, window, cx),
14073                                HoverLink::Url(_) => Task::ready(Ok(None)),
14074                                HoverLink::File(_) => Task::ready(Ok(None)),
14075                            })
14076                            .collect::<Vec<_>>();
14077                        (title, location_tasks, editor.workspace().clone())
14078                    })
14079                    .context("location tasks preparation")?;
14080
14081                let locations = future::join_all(location_tasks)
14082                    .await
14083                    .into_iter()
14084                    .filter_map(|location| location.transpose())
14085                    .collect::<Result<_>>()
14086                    .context("location tasks")?;
14087
14088                let Some(workspace) = workspace else {
14089                    return Ok(Navigated::No);
14090                };
14091                let opened = workspace
14092                    .update_in(cx, |workspace, window, cx| {
14093                        Self::open_locations_in_multibuffer(
14094                            workspace,
14095                            locations,
14096                            title,
14097                            split,
14098                            MultibufferSelectionMode::First,
14099                            window,
14100                            cx,
14101                        )
14102                    })
14103                    .ok();
14104
14105                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14106            })
14107        } else {
14108            Task::ready(Ok(Navigated::No))
14109        }
14110    }
14111
14112    fn compute_target_location(
14113        &self,
14114        lsp_location: lsp::Location,
14115        server_id: LanguageServerId,
14116        window: &mut Window,
14117        cx: &mut Context<Self>,
14118    ) -> Task<anyhow::Result<Option<Location>>> {
14119        let Some(project) = self.project.clone() else {
14120            return Task::ready(Ok(None));
14121        };
14122
14123        cx.spawn_in(window, async move |editor, cx| {
14124            let location_task = editor.update(cx, |_, cx| {
14125                project.update(cx, |project, cx| {
14126                    let language_server_name = project
14127                        .language_server_statuses(cx)
14128                        .find(|(id, _)| server_id == *id)
14129                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14130                    language_server_name.map(|language_server_name| {
14131                        project.open_local_buffer_via_lsp(
14132                            lsp_location.uri.clone(),
14133                            server_id,
14134                            language_server_name,
14135                            cx,
14136                        )
14137                    })
14138                })
14139            })?;
14140            let location = match location_task {
14141                Some(task) => Some({
14142                    let target_buffer_handle = task.await.context("open local buffer")?;
14143                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14144                        let target_start = target_buffer
14145                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14146                        let target_end = target_buffer
14147                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14148                        target_buffer.anchor_after(target_start)
14149                            ..target_buffer.anchor_before(target_end)
14150                    })?;
14151                    Location {
14152                        buffer: target_buffer_handle,
14153                        range,
14154                    }
14155                }),
14156                None => None,
14157            };
14158            Ok(location)
14159        })
14160    }
14161
14162    pub fn find_all_references(
14163        &mut self,
14164        _: &FindAllReferences,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) -> Option<Task<Result<Navigated>>> {
14168        let selection = self.selections.newest::<usize>(cx);
14169        let multi_buffer = self.buffer.read(cx);
14170        let head = selection.head();
14171
14172        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14173        let head_anchor = multi_buffer_snapshot.anchor_at(
14174            head,
14175            if head < selection.tail() {
14176                Bias::Right
14177            } else {
14178                Bias::Left
14179            },
14180        );
14181
14182        match self
14183            .find_all_references_task_sources
14184            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14185        {
14186            Ok(_) => {
14187                log::info!(
14188                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14189                );
14190                return None;
14191            }
14192            Err(i) => {
14193                self.find_all_references_task_sources.insert(i, head_anchor);
14194            }
14195        }
14196
14197        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14198        let workspace = self.workspace()?;
14199        let project = workspace.read(cx).project().clone();
14200        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14201        Some(cx.spawn_in(window, async move |editor, cx| {
14202            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14203                if let Ok(i) = editor
14204                    .find_all_references_task_sources
14205                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14206                {
14207                    editor.find_all_references_task_sources.remove(i);
14208                }
14209            });
14210
14211            let locations = references.await?;
14212            if locations.is_empty() {
14213                return anyhow::Ok(Navigated::No);
14214            }
14215
14216            workspace.update_in(cx, |workspace, window, cx| {
14217                let title = locations
14218                    .first()
14219                    .as_ref()
14220                    .map(|location| {
14221                        let buffer = location.buffer.read(cx);
14222                        format!(
14223                            "References to `{}`",
14224                            buffer
14225                                .text_for_range(location.range.clone())
14226                                .collect::<String>()
14227                        )
14228                    })
14229                    .unwrap();
14230                Self::open_locations_in_multibuffer(
14231                    workspace,
14232                    locations,
14233                    title,
14234                    false,
14235                    MultibufferSelectionMode::First,
14236                    window,
14237                    cx,
14238                );
14239                Navigated::Yes
14240            })
14241        }))
14242    }
14243
14244    /// Opens a multibuffer with the given project locations in it
14245    pub fn open_locations_in_multibuffer(
14246        workspace: &mut Workspace,
14247        mut locations: Vec<Location>,
14248        title: String,
14249        split: bool,
14250        multibuffer_selection_mode: MultibufferSelectionMode,
14251        window: &mut Window,
14252        cx: &mut Context<Workspace>,
14253    ) {
14254        // If there are multiple definitions, open them in a multibuffer
14255        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14256        let mut locations = locations.into_iter().peekable();
14257        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14258        let capability = workspace.project().read(cx).capability();
14259
14260        let excerpt_buffer = cx.new(|cx| {
14261            let mut multibuffer = MultiBuffer::new(capability);
14262            while let Some(location) = locations.next() {
14263                let buffer = location.buffer.read(cx);
14264                let mut ranges_for_buffer = Vec::new();
14265                let range = location.range.to_point(buffer);
14266                ranges_for_buffer.push(range.clone());
14267
14268                while let Some(next_location) = locations.peek() {
14269                    if next_location.buffer == location.buffer {
14270                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14271                        locations.next();
14272                    } else {
14273                        break;
14274                    }
14275                }
14276
14277                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14278                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14279                    PathKey::for_buffer(&location.buffer, cx),
14280                    location.buffer.clone(),
14281                    ranges_for_buffer,
14282                    DEFAULT_MULTIBUFFER_CONTEXT,
14283                    cx,
14284                );
14285                ranges.extend(new_ranges)
14286            }
14287
14288            multibuffer.with_title(title)
14289        });
14290
14291        let editor = cx.new(|cx| {
14292            Editor::for_multibuffer(
14293                excerpt_buffer,
14294                Some(workspace.project().clone()),
14295                window,
14296                cx,
14297            )
14298        });
14299        editor.update(cx, |editor, cx| {
14300            match multibuffer_selection_mode {
14301                MultibufferSelectionMode::First => {
14302                    if let Some(first_range) = ranges.first() {
14303                        editor.change_selections(None, window, cx, |selections| {
14304                            selections.clear_disjoint();
14305                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14306                        });
14307                    }
14308                    editor.highlight_background::<Self>(
14309                        &ranges,
14310                        |theme| theme.editor_highlighted_line_background,
14311                        cx,
14312                    );
14313                }
14314                MultibufferSelectionMode::All => {
14315                    editor.change_selections(None, window, cx, |selections| {
14316                        selections.clear_disjoint();
14317                        selections.select_anchor_ranges(ranges);
14318                    });
14319                }
14320            }
14321            editor.register_buffers_with_language_servers(cx);
14322        });
14323
14324        let item = Box::new(editor);
14325        let item_id = item.item_id();
14326
14327        if split {
14328            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14329        } else {
14330            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14331                let (preview_item_id, preview_item_idx) =
14332                    workspace.active_pane().update(cx, |pane, _| {
14333                        (pane.preview_item_id(), pane.preview_item_idx())
14334                    });
14335
14336                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14337
14338                if let Some(preview_item_id) = preview_item_id {
14339                    workspace.active_pane().update(cx, |pane, cx| {
14340                        pane.remove_item(preview_item_id, false, false, window, cx);
14341                    });
14342                }
14343            } else {
14344                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14345            }
14346        }
14347        workspace.active_pane().update(cx, |pane, cx| {
14348            pane.set_preview_item_id(Some(item_id), cx);
14349        });
14350    }
14351
14352    pub fn rename(
14353        &mut self,
14354        _: &Rename,
14355        window: &mut Window,
14356        cx: &mut Context<Self>,
14357    ) -> Option<Task<Result<()>>> {
14358        use language::ToOffset as _;
14359
14360        let provider = self.semantics_provider.clone()?;
14361        let selection = self.selections.newest_anchor().clone();
14362        let (cursor_buffer, cursor_buffer_position) = self
14363            .buffer
14364            .read(cx)
14365            .text_anchor_for_position(selection.head(), cx)?;
14366        let (tail_buffer, cursor_buffer_position_end) = self
14367            .buffer
14368            .read(cx)
14369            .text_anchor_for_position(selection.tail(), cx)?;
14370        if tail_buffer != cursor_buffer {
14371            return None;
14372        }
14373
14374        let snapshot = cursor_buffer.read(cx).snapshot();
14375        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14376        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14377        let prepare_rename = provider
14378            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14379            .unwrap_or_else(|| Task::ready(Ok(None)));
14380        drop(snapshot);
14381
14382        Some(cx.spawn_in(window, async move |this, cx| {
14383            let rename_range = if let Some(range) = prepare_rename.await? {
14384                Some(range)
14385            } else {
14386                this.update(cx, |this, cx| {
14387                    let buffer = this.buffer.read(cx).snapshot(cx);
14388                    let mut buffer_highlights = this
14389                        .document_highlights_for_position(selection.head(), &buffer)
14390                        .filter(|highlight| {
14391                            highlight.start.excerpt_id == selection.head().excerpt_id
14392                                && highlight.end.excerpt_id == selection.head().excerpt_id
14393                        });
14394                    buffer_highlights
14395                        .next()
14396                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14397                })?
14398            };
14399            if let Some(rename_range) = rename_range {
14400                this.update_in(cx, |this, window, cx| {
14401                    let snapshot = cursor_buffer.read(cx).snapshot();
14402                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14403                    let cursor_offset_in_rename_range =
14404                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14405                    let cursor_offset_in_rename_range_end =
14406                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14407
14408                    this.take_rename(false, window, cx);
14409                    let buffer = this.buffer.read(cx).read(cx);
14410                    let cursor_offset = selection.head().to_offset(&buffer);
14411                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14412                    let rename_end = rename_start + rename_buffer_range.len();
14413                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14414                    let mut old_highlight_id = None;
14415                    let old_name: Arc<str> = buffer
14416                        .chunks(rename_start..rename_end, true)
14417                        .map(|chunk| {
14418                            if old_highlight_id.is_none() {
14419                                old_highlight_id = chunk.syntax_highlight_id;
14420                            }
14421                            chunk.text
14422                        })
14423                        .collect::<String>()
14424                        .into();
14425
14426                    drop(buffer);
14427
14428                    // Position the selection in the rename editor so that it matches the current selection.
14429                    this.show_local_selections = false;
14430                    let rename_editor = cx.new(|cx| {
14431                        let mut editor = Editor::single_line(window, cx);
14432                        editor.buffer.update(cx, |buffer, cx| {
14433                            buffer.edit([(0..0, old_name.clone())], None, cx)
14434                        });
14435                        let rename_selection_range = match cursor_offset_in_rename_range
14436                            .cmp(&cursor_offset_in_rename_range_end)
14437                        {
14438                            Ordering::Equal => {
14439                                editor.select_all(&SelectAll, window, cx);
14440                                return editor;
14441                            }
14442                            Ordering::Less => {
14443                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14444                            }
14445                            Ordering::Greater => {
14446                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14447                            }
14448                        };
14449                        if rename_selection_range.end > old_name.len() {
14450                            editor.select_all(&SelectAll, window, cx);
14451                        } else {
14452                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14453                                s.select_ranges([rename_selection_range]);
14454                            });
14455                        }
14456                        editor
14457                    });
14458                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14459                        if e == &EditorEvent::Focused {
14460                            cx.emit(EditorEvent::FocusedIn)
14461                        }
14462                    })
14463                    .detach();
14464
14465                    let write_highlights =
14466                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14467                    let read_highlights =
14468                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14469                    let ranges = write_highlights
14470                        .iter()
14471                        .flat_map(|(_, ranges)| ranges.iter())
14472                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14473                        .cloned()
14474                        .collect();
14475
14476                    this.highlight_text::<Rename>(
14477                        ranges,
14478                        HighlightStyle {
14479                            fade_out: Some(0.6),
14480                            ..Default::default()
14481                        },
14482                        cx,
14483                    );
14484                    let rename_focus_handle = rename_editor.focus_handle(cx);
14485                    window.focus(&rename_focus_handle);
14486                    let block_id = this.insert_blocks(
14487                        [BlockProperties {
14488                            style: BlockStyle::Flex,
14489                            placement: BlockPlacement::Below(range.start),
14490                            height: Some(1),
14491                            render: Arc::new({
14492                                let rename_editor = rename_editor.clone();
14493                                move |cx: &mut BlockContext| {
14494                                    let mut text_style = cx.editor_style.text.clone();
14495                                    if let Some(highlight_style) = old_highlight_id
14496                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14497                                    {
14498                                        text_style = text_style.highlight(highlight_style);
14499                                    }
14500                                    div()
14501                                        .block_mouse_down()
14502                                        .pl(cx.anchor_x)
14503                                        .child(EditorElement::new(
14504                                            &rename_editor,
14505                                            EditorStyle {
14506                                                background: cx.theme().system().transparent,
14507                                                local_player: cx.editor_style.local_player,
14508                                                text: text_style,
14509                                                scrollbar_width: cx.editor_style.scrollbar_width,
14510                                                syntax: cx.editor_style.syntax.clone(),
14511                                                status: cx.editor_style.status.clone(),
14512                                                inlay_hints_style: HighlightStyle {
14513                                                    font_weight: Some(FontWeight::BOLD),
14514                                                    ..make_inlay_hints_style(cx.app)
14515                                                },
14516                                                inline_completion_styles: make_suggestion_styles(
14517                                                    cx.app,
14518                                                ),
14519                                                ..EditorStyle::default()
14520                                            },
14521                                        ))
14522                                        .into_any_element()
14523                                }
14524                            }),
14525                            priority: 0,
14526                        }],
14527                        Some(Autoscroll::fit()),
14528                        cx,
14529                    )[0];
14530                    this.pending_rename = Some(RenameState {
14531                        range,
14532                        old_name,
14533                        editor: rename_editor,
14534                        block_id,
14535                    });
14536                })?;
14537            }
14538
14539            Ok(())
14540        }))
14541    }
14542
14543    pub fn confirm_rename(
14544        &mut self,
14545        _: &ConfirmRename,
14546        window: &mut Window,
14547        cx: &mut Context<Self>,
14548    ) -> Option<Task<Result<()>>> {
14549        let rename = self.take_rename(false, window, cx)?;
14550        let workspace = self.workspace()?.downgrade();
14551        let (buffer, start) = self
14552            .buffer
14553            .read(cx)
14554            .text_anchor_for_position(rename.range.start, cx)?;
14555        let (end_buffer, _) = self
14556            .buffer
14557            .read(cx)
14558            .text_anchor_for_position(rename.range.end, cx)?;
14559        if buffer != end_buffer {
14560            return None;
14561        }
14562
14563        let old_name = rename.old_name;
14564        let new_name = rename.editor.read(cx).text(cx);
14565
14566        let rename = self.semantics_provider.as_ref()?.perform_rename(
14567            &buffer,
14568            start,
14569            new_name.clone(),
14570            cx,
14571        )?;
14572
14573        Some(cx.spawn_in(window, async move |editor, cx| {
14574            let project_transaction = rename.await?;
14575            Self::open_project_transaction(
14576                &editor,
14577                workspace,
14578                project_transaction,
14579                format!("Rename: {}{}", old_name, new_name),
14580                cx,
14581            )
14582            .await?;
14583
14584            editor.update(cx, |editor, cx| {
14585                editor.refresh_document_highlights(cx);
14586            })?;
14587            Ok(())
14588        }))
14589    }
14590
14591    fn take_rename(
14592        &mut self,
14593        moving_cursor: bool,
14594        window: &mut Window,
14595        cx: &mut Context<Self>,
14596    ) -> Option<RenameState> {
14597        let rename = self.pending_rename.take()?;
14598        if rename.editor.focus_handle(cx).is_focused(window) {
14599            window.focus(&self.focus_handle);
14600        }
14601
14602        self.remove_blocks(
14603            [rename.block_id].into_iter().collect(),
14604            Some(Autoscroll::fit()),
14605            cx,
14606        );
14607        self.clear_highlights::<Rename>(cx);
14608        self.show_local_selections = true;
14609
14610        if moving_cursor {
14611            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14612                editor.selections.newest::<usize>(cx).head()
14613            });
14614
14615            // Update the selection to match the position of the selection inside
14616            // the rename editor.
14617            let snapshot = self.buffer.read(cx).read(cx);
14618            let rename_range = rename.range.to_offset(&snapshot);
14619            let cursor_in_editor = snapshot
14620                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14621                .min(rename_range.end);
14622            drop(snapshot);
14623
14624            self.change_selections(None, window, cx, |s| {
14625                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14626            });
14627        } else {
14628            self.refresh_document_highlights(cx);
14629        }
14630
14631        Some(rename)
14632    }
14633
14634    pub fn pending_rename(&self) -> Option<&RenameState> {
14635        self.pending_rename.as_ref()
14636    }
14637
14638    fn format(
14639        &mut self,
14640        _: &Format,
14641        window: &mut Window,
14642        cx: &mut Context<Self>,
14643    ) -> Option<Task<Result<()>>> {
14644        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14645
14646        let project = match &self.project {
14647            Some(project) => project.clone(),
14648            None => return None,
14649        };
14650
14651        Some(self.perform_format(
14652            project,
14653            FormatTrigger::Manual,
14654            FormatTarget::Buffers,
14655            window,
14656            cx,
14657        ))
14658    }
14659
14660    fn format_selections(
14661        &mut self,
14662        _: &FormatSelections,
14663        window: &mut Window,
14664        cx: &mut Context<Self>,
14665    ) -> Option<Task<Result<()>>> {
14666        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14667
14668        let project = match &self.project {
14669            Some(project) => project.clone(),
14670            None => return None,
14671        };
14672
14673        let ranges = self
14674            .selections
14675            .all_adjusted(cx)
14676            .into_iter()
14677            .map(|selection| selection.range())
14678            .collect_vec();
14679
14680        Some(self.perform_format(
14681            project,
14682            FormatTrigger::Manual,
14683            FormatTarget::Ranges(ranges),
14684            window,
14685            cx,
14686        ))
14687    }
14688
14689    fn perform_format(
14690        &mut self,
14691        project: Entity<Project>,
14692        trigger: FormatTrigger,
14693        target: FormatTarget,
14694        window: &mut Window,
14695        cx: &mut Context<Self>,
14696    ) -> Task<Result<()>> {
14697        let buffer = self.buffer.clone();
14698        let (buffers, target) = match target {
14699            FormatTarget::Buffers => {
14700                let mut buffers = buffer.read(cx).all_buffers();
14701                if trigger == FormatTrigger::Save {
14702                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
14703                }
14704                (buffers, LspFormatTarget::Buffers)
14705            }
14706            FormatTarget::Ranges(selection_ranges) => {
14707                let multi_buffer = buffer.read(cx);
14708                let snapshot = multi_buffer.read(cx);
14709                let mut buffers = HashSet::default();
14710                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
14711                    BTreeMap::new();
14712                for selection_range in selection_ranges {
14713                    for (buffer, buffer_range, _) in
14714                        snapshot.range_to_buffer_ranges(selection_range)
14715                    {
14716                        let buffer_id = buffer.remote_id();
14717                        let start = buffer.anchor_before(buffer_range.start);
14718                        let end = buffer.anchor_after(buffer_range.end);
14719                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
14720                        buffer_id_to_ranges
14721                            .entry(buffer_id)
14722                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
14723                            .or_insert_with(|| vec![start..end]);
14724                    }
14725                }
14726                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
14727            }
14728        };
14729
14730        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
14731        let selections_prev = transaction_id_prev
14732            .and_then(|transaction_id_prev| {
14733                // default to selections as they were after the last edit, if we have them,
14734                // instead of how they are now.
14735                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
14736                // will take you back to where you made the last edit, instead of staying where you scrolled
14737                self.selection_history
14738                    .transaction(transaction_id_prev)
14739                    .map(|t| t.0.clone())
14740            })
14741            .unwrap_or_else(|| {
14742                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
14743                self.selections.disjoint_anchors()
14744            });
14745
14746        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
14747        let format = project.update(cx, |project, cx| {
14748            project.format(buffers, target, true, trigger, cx)
14749        });
14750
14751        cx.spawn_in(window, async move |editor, cx| {
14752            let transaction = futures::select_biased! {
14753                transaction = format.log_err().fuse() => transaction,
14754                () = timeout => {
14755                    log::warn!("timed out waiting for formatting");
14756                    None
14757                }
14758            };
14759
14760            buffer
14761                .update(cx, |buffer, cx| {
14762                    if let Some(transaction) = transaction {
14763                        if !buffer.is_singleton() {
14764                            buffer.push_transaction(&transaction.0, cx);
14765                        }
14766                    }
14767                    cx.notify();
14768                })
14769                .ok();
14770
14771            if let Some(transaction_id_now) =
14772                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
14773            {
14774                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
14775                if has_new_transaction {
14776                    _ = editor.update(cx, |editor, _| {
14777                        editor
14778                            .selection_history
14779                            .insert_transaction(transaction_id_now, selections_prev);
14780                    });
14781                }
14782            }
14783
14784            Ok(())
14785        })
14786    }
14787
14788    fn organize_imports(
14789        &mut self,
14790        _: &OrganizeImports,
14791        window: &mut Window,
14792        cx: &mut Context<Self>,
14793    ) -> Option<Task<Result<()>>> {
14794        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14795        let project = match &self.project {
14796            Some(project) => project.clone(),
14797            None => return None,
14798        };
14799        Some(self.perform_code_action_kind(
14800            project,
14801            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
14802            window,
14803            cx,
14804        ))
14805    }
14806
14807    fn perform_code_action_kind(
14808        &mut self,
14809        project: Entity<Project>,
14810        kind: CodeActionKind,
14811        window: &mut Window,
14812        cx: &mut Context<Self>,
14813    ) -> Task<Result<()>> {
14814        let buffer = self.buffer.clone();
14815        let buffers = buffer.read(cx).all_buffers();
14816        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
14817        let apply_action = project.update(cx, |project, cx| {
14818            project.apply_code_action_kind(buffers, kind, true, cx)
14819        });
14820        cx.spawn_in(window, async move |_, cx| {
14821            let transaction = futures::select_biased! {
14822                () = timeout => {
14823                    log::warn!("timed out waiting for executing code action");
14824                    None
14825                }
14826                transaction = apply_action.log_err().fuse() => transaction,
14827            };
14828            buffer
14829                .update(cx, |buffer, cx| {
14830                    // check if we need this
14831                    if let Some(transaction) = transaction {
14832                        if !buffer.is_singleton() {
14833                            buffer.push_transaction(&transaction.0, cx);
14834                        }
14835                    }
14836                    cx.notify();
14837                })
14838                .ok();
14839            Ok(())
14840        })
14841    }
14842
14843    fn restart_language_server(
14844        &mut self,
14845        _: &RestartLanguageServer,
14846        _: &mut Window,
14847        cx: &mut Context<Self>,
14848    ) {
14849        if let Some(project) = self.project.clone() {
14850            self.buffer.update(cx, |multi_buffer, cx| {
14851                project.update(cx, |project, cx| {
14852                    project.restart_language_servers_for_buffers(
14853                        multi_buffer.all_buffers().into_iter().collect(),
14854                        cx,
14855                    );
14856                });
14857            })
14858        }
14859    }
14860
14861    fn stop_language_server(
14862        &mut self,
14863        _: &StopLanguageServer,
14864        _: &mut Window,
14865        cx: &mut Context<Self>,
14866    ) {
14867        if let Some(project) = self.project.clone() {
14868            self.buffer.update(cx, |multi_buffer, cx| {
14869                project.update(cx, |project, cx| {
14870                    project.stop_language_servers_for_buffers(
14871                        multi_buffer.all_buffers().into_iter().collect(),
14872                        cx,
14873                    );
14874                    cx.emit(project::Event::RefreshInlayHints);
14875                });
14876            });
14877        }
14878    }
14879
14880    fn cancel_language_server_work(
14881        workspace: &mut Workspace,
14882        _: &actions::CancelLanguageServerWork,
14883        _: &mut Window,
14884        cx: &mut Context<Workspace>,
14885    ) {
14886        let project = workspace.project();
14887        let buffers = workspace
14888            .active_item(cx)
14889            .and_then(|item| item.act_as::<Editor>(cx))
14890            .map_or(HashSet::default(), |editor| {
14891                editor.read(cx).buffer.read(cx).all_buffers()
14892            });
14893        project.update(cx, |project, cx| {
14894            project.cancel_language_server_work_for_buffers(buffers, cx);
14895        });
14896    }
14897
14898    fn show_character_palette(
14899        &mut self,
14900        _: &ShowCharacterPalette,
14901        window: &mut Window,
14902        _: &mut Context<Self>,
14903    ) {
14904        window.show_character_palette();
14905    }
14906
14907    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
14908        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
14909            let buffer = self.buffer.read(cx).snapshot(cx);
14910            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
14911            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
14912            let is_valid = buffer
14913                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
14914                .any(|entry| {
14915                    entry.diagnostic.is_primary
14916                        && !entry.range.is_empty()
14917                        && entry.range.start == primary_range_start
14918                        && entry.diagnostic.message == active_diagnostics.active_message
14919                });
14920
14921            if !is_valid {
14922                self.dismiss_diagnostics(cx);
14923            }
14924        }
14925    }
14926
14927    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
14928        match &self.active_diagnostics {
14929            ActiveDiagnostic::Group(group) => Some(group),
14930            _ => None,
14931        }
14932    }
14933
14934    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
14935        self.dismiss_diagnostics(cx);
14936        self.active_diagnostics = ActiveDiagnostic::All;
14937    }
14938
14939    fn activate_diagnostics(
14940        &mut self,
14941        buffer_id: BufferId,
14942        diagnostic: DiagnosticEntry<usize>,
14943        window: &mut Window,
14944        cx: &mut Context<Self>,
14945    ) {
14946        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
14947            return;
14948        }
14949        self.dismiss_diagnostics(cx);
14950        let snapshot = self.snapshot(window, cx);
14951        let buffer = self.buffer.read(cx).snapshot(cx);
14952        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
14953            return;
14954        };
14955
14956        let diagnostic_group = buffer
14957            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
14958            .collect::<Vec<_>>();
14959
14960        let blocks =
14961            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
14962
14963        let blocks = self.display_map.update(cx, |display_map, cx| {
14964            display_map.insert_blocks(blocks, cx).into_iter().collect()
14965        });
14966        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
14967            active_range: buffer.anchor_before(diagnostic.range.start)
14968                ..buffer.anchor_after(diagnostic.range.end),
14969            active_message: diagnostic.diagnostic.message.clone(),
14970            group_id: diagnostic.diagnostic.group_id,
14971            blocks,
14972        });
14973        cx.notify();
14974    }
14975
14976    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
14977        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
14978            return;
14979        };
14980
14981        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
14982        if let ActiveDiagnostic::Group(group) = prev {
14983            self.display_map.update(cx, |display_map, cx| {
14984                display_map.remove_blocks(group.blocks, cx);
14985            });
14986            cx.notify();
14987        }
14988    }
14989
14990    /// Disable inline diagnostics rendering for this editor.
14991    pub fn disable_inline_diagnostics(&mut self) {
14992        self.inline_diagnostics_enabled = false;
14993        self.inline_diagnostics_update = Task::ready(());
14994        self.inline_diagnostics.clear();
14995    }
14996
14997    pub fn inline_diagnostics_enabled(&self) -> bool {
14998        self.inline_diagnostics_enabled
14999    }
15000
15001    pub fn show_inline_diagnostics(&self) -> bool {
15002        self.show_inline_diagnostics
15003    }
15004
15005    pub fn toggle_inline_diagnostics(
15006        &mut self,
15007        _: &ToggleInlineDiagnostics,
15008        window: &mut Window,
15009        cx: &mut Context<Editor>,
15010    ) {
15011        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15012        self.refresh_inline_diagnostics(false, window, cx);
15013    }
15014
15015    fn refresh_inline_diagnostics(
15016        &mut self,
15017        debounce: bool,
15018        window: &mut Window,
15019        cx: &mut Context<Self>,
15020    ) {
15021        if !self.inline_diagnostics_enabled || !self.show_inline_diagnostics {
15022            self.inline_diagnostics_update = Task::ready(());
15023            self.inline_diagnostics.clear();
15024            return;
15025        }
15026
15027        let debounce_ms = ProjectSettings::get_global(cx)
15028            .diagnostics
15029            .inline
15030            .update_debounce_ms;
15031        let debounce = if debounce && debounce_ms > 0 {
15032            Some(Duration::from_millis(debounce_ms))
15033        } else {
15034            None
15035        };
15036        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15037            let editor = editor.upgrade().unwrap();
15038
15039            if let Some(debounce) = debounce {
15040                cx.background_executor().timer(debounce).await;
15041            }
15042            let Some(snapshot) = editor
15043                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15044                .ok()
15045            else {
15046                return;
15047            };
15048
15049            let new_inline_diagnostics = cx
15050                .background_spawn(async move {
15051                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15052                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15053                        let message = diagnostic_entry
15054                            .diagnostic
15055                            .message
15056                            .split_once('\n')
15057                            .map(|(line, _)| line)
15058                            .map(SharedString::new)
15059                            .unwrap_or_else(|| {
15060                                SharedString::from(diagnostic_entry.diagnostic.message)
15061                            });
15062                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15063                        let (Ok(i) | Err(i)) = inline_diagnostics
15064                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15065                        inline_diagnostics.insert(
15066                            i,
15067                            (
15068                                start_anchor,
15069                                InlineDiagnostic {
15070                                    message,
15071                                    group_id: diagnostic_entry.diagnostic.group_id,
15072                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15073                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15074                                    severity: diagnostic_entry.diagnostic.severity,
15075                                },
15076                            ),
15077                        );
15078                    }
15079                    inline_diagnostics
15080                })
15081                .await;
15082
15083            editor
15084                .update(cx, |editor, cx| {
15085                    editor.inline_diagnostics = new_inline_diagnostics;
15086                    cx.notify();
15087                })
15088                .ok();
15089        });
15090    }
15091
15092    pub fn set_selections_from_remote(
15093        &mut self,
15094        selections: Vec<Selection<Anchor>>,
15095        pending_selection: Option<Selection<Anchor>>,
15096        window: &mut Window,
15097        cx: &mut Context<Self>,
15098    ) {
15099        let old_cursor_position = self.selections.newest_anchor().head();
15100        self.selections.change_with(cx, |s| {
15101            s.select_anchors(selections);
15102            if let Some(pending_selection) = pending_selection {
15103                s.set_pending(pending_selection, SelectMode::Character);
15104            } else {
15105                s.clear_pending();
15106            }
15107        });
15108        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15109    }
15110
15111    fn push_to_selection_history(&mut self) {
15112        self.selection_history.push(SelectionHistoryEntry {
15113            selections: self.selections.disjoint_anchors(),
15114            select_next_state: self.select_next_state.clone(),
15115            select_prev_state: self.select_prev_state.clone(),
15116            add_selections_state: self.add_selections_state.clone(),
15117        });
15118    }
15119
15120    pub fn transact(
15121        &mut self,
15122        window: &mut Window,
15123        cx: &mut Context<Self>,
15124        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15125    ) -> Option<TransactionId> {
15126        self.start_transaction_at(Instant::now(), window, cx);
15127        update(self, window, cx);
15128        self.end_transaction_at(Instant::now(), cx)
15129    }
15130
15131    pub fn start_transaction_at(
15132        &mut self,
15133        now: Instant,
15134        window: &mut Window,
15135        cx: &mut Context<Self>,
15136    ) {
15137        self.end_selection(window, cx);
15138        if let Some(tx_id) = self
15139            .buffer
15140            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15141        {
15142            self.selection_history
15143                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15144            cx.emit(EditorEvent::TransactionBegun {
15145                transaction_id: tx_id,
15146            })
15147        }
15148    }
15149
15150    pub fn end_transaction_at(
15151        &mut self,
15152        now: Instant,
15153        cx: &mut Context<Self>,
15154    ) -> Option<TransactionId> {
15155        if let Some(transaction_id) = self
15156            .buffer
15157            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15158        {
15159            if let Some((_, end_selections)) =
15160                self.selection_history.transaction_mut(transaction_id)
15161            {
15162                *end_selections = Some(self.selections.disjoint_anchors());
15163            } else {
15164                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15165            }
15166
15167            cx.emit(EditorEvent::Edited { transaction_id });
15168            Some(transaction_id)
15169        } else {
15170            None
15171        }
15172    }
15173
15174    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15175        if self.selection_mark_mode {
15176            self.change_selections(None, window, cx, |s| {
15177                s.move_with(|_, sel| {
15178                    sel.collapse_to(sel.head(), SelectionGoal::None);
15179                });
15180            })
15181        }
15182        self.selection_mark_mode = true;
15183        cx.notify();
15184    }
15185
15186    pub fn swap_selection_ends(
15187        &mut self,
15188        _: &actions::SwapSelectionEnds,
15189        window: &mut Window,
15190        cx: &mut Context<Self>,
15191    ) {
15192        self.change_selections(None, window, cx, |s| {
15193            s.move_with(|_, sel| {
15194                if sel.start != sel.end {
15195                    sel.reversed = !sel.reversed
15196                }
15197            });
15198        });
15199        self.request_autoscroll(Autoscroll::newest(), cx);
15200        cx.notify();
15201    }
15202
15203    pub fn toggle_fold(
15204        &mut self,
15205        _: &actions::ToggleFold,
15206        window: &mut Window,
15207        cx: &mut Context<Self>,
15208    ) {
15209        if self.is_singleton(cx) {
15210            let selection = self.selections.newest::<Point>(cx);
15211
15212            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15213            let range = if selection.is_empty() {
15214                let point = selection.head().to_display_point(&display_map);
15215                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15216                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15217                    .to_point(&display_map);
15218                start..end
15219            } else {
15220                selection.range()
15221            };
15222            if display_map.folds_in_range(range).next().is_some() {
15223                self.unfold_lines(&Default::default(), window, cx)
15224            } else {
15225                self.fold(&Default::default(), window, cx)
15226            }
15227        } else {
15228            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15229            let buffer_ids: HashSet<_> = self
15230                .selections
15231                .disjoint_anchor_ranges()
15232                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15233                .collect();
15234
15235            let should_unfold = buffer_ids
15236                .iter()
15237                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15238
15239            for buffer_id in buffer_ids {
15240                if should_unfold {
15241                    self.unfold_buffer(buffer_id, cx);
15242                } else {
15243                    self.fold_buffer(buffer_id, cx);
15244                }
15245            }
15246        }
15247    }
15248
15249    pub fn toggle_fold_recursive(
15250        &mut self,
15251        _: &actions::ToggleFoldRecursive,
15252        window: &mut Window,
15253        cx: &mut Context<Self>,
15254    ) {
15255        let selection = self.selections.newest::<Point>(cx);
15256
15257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15258        let range = if selection.is_empty() {
15259            let point = selection.head().to_display_point(&display_map);
15260            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15261            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15262                .to_point(&display_map);
15263            start..end
15264        } else {
15265            selection.range()
15266        };
15267        if display_map.folds_in_range(range).next().is_some() {
15268            self.unfold_recursive(&Default::default(), window, cx)
15269        } else {
15270            self.fold_recursive(&Default::default(), window, cx)
15271        }
15272    }
15273
15274    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15275        if self.is_singleton(cx) {
15276            let mut to_fold = Vec::new();
15277            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15278            let selections = self.selections.all_adjusted(cx);
15279
15280            for selection in selections {
15281                let range = selection.range().sorted();
15282                let buffer_start_row = range.start.row;
15283
15284                if range.start.row != range.end.row {
15285                    let mut found = false;
15286                    let mut row = range.start.row;
15287                    while row <= range.end.row {
15288                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15289                        {
15290                            found = true;
15291                            row = crease.range().end.row + 1;
15292                            to_fold.push(crease);
15293                        } else {
15294                            row += 1
15295                        }
15296                    }
15297                    if found {
15298                        continue;
15299                    }
15300                }
15301
15302                for row in (0..=range.start.row).rev() {
15303                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15304                        if crease.range().end.row >= buffer_start_row {
15305                            to_fold.push(crease);
15306                            if row <= range.start.row {
15307                                break;
15308                            }
15309                        }
15310                    }
15311                }
15312            }
15313
15314            self.fold_creases(to_fold, true, window, cx);
15315        } else {
15316            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15317            let buffer_ids = self
15318                .selections
15319                .disjoint_anchor_ranges()
15320                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15321                .collect::<HashSet<_>>();
15322            for buffer_id in buffer_ids {
15323                self.fold_buffer(buffer_id, cx);
15324            }
15325        }
15326    }
15327
15328    fn fold_at_level(
15329        &mut self,
15330        fold_at: &FoldAtLevel,
15331        window: &mut Window,
15332        cx: &mut Context<Self>,
15333    ) {
15334        if !self.buffer.read(cx).is_singleton() {
15335            return;
15336        }
15337
15338        let fold_at_level = fold_at.0;
15339        let snapshot = self.buffer.read(cx).snapshot(cx);
15340        let mut to_fold = Vec::new();
15341        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15342
15343        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15344            while start_row < end_row {
15345                match self
15346                    .snapshot(window, cx)
15347                    .crease_for_buffer_row(MultiBufferRow(start_row))
15348                {
15349                    Some(crease) => {
15350                        let nested_start_row = crease.range().start.row + 1;
15351                        let nested_end_row = crease.range().end.row;
15352
15353                        if current_level < fold_at_level {
15354                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15355                        } else if current_level == fold_at_level {
15356                            to_fold.push(crease);
15357                        }
15358
15359                        start_row = nested_end_row + 1;
15360                    }
15361                    None => start_row += 1,
15362                }
15363            }
15364        }
15365
15366        self.fold_creases(to_fold, true, window, cx);
15367    }
15368
15369    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15370        if self.buffer.read(cx).is_singleton() {
15371            let mut fold_ranges = Vec::new();
15372            let snapshot = self.buffer.read(cx).snapshot(cx);
15373
15374            for row in 0..snapshot.max_row().0 {
15375                if let Some(foldable_range) = self
15376                    .snapshot(window, cx)
15377                    .crease_for_buffer_row(MultiBufferRow(row))
15378                {
15379                    fold_ranges.push(foldable_range);
15380                }
15381            }
15382
15383            self.fold_creases(fold_ranges, true, window, cx);
15384        } else {
15385            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15386                editor
15387                    .update_in(cx, |editor, _, cx| {
15388                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15389                            editor.fold_buffer(buffer_id, cx);
15390                        }
15391                    })
15392                    .ok();
15393            });
15394        }
15395    }
15396
15397    pub fn fold_function_bodies(
15398        &mut self,
15399        _: &actions::FoldFunctionBodies,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) {
15403        let snapshot = self.buffer.read(cx).snapshot(cx);
15404
15405        let ranges = snapshot
15406            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15407            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15408            .collect::<Vec<_>>();
15409
15410        let creases = ranges
15411            .into_iter()
15412            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15413            .collect();
15414
15415        self.fold_creases(creases, true, window, cx);
15416    }
15417
15418    pub fn fold_recursive(
15419        &mut self,
15420        _: &actions::FoldRecursive,
15421        window: &mut Window,
15422        cx: &mut Context<Self>,
15423    ) {
15424        let mut to_fold = Vec::new();
15425        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15426        let selections = self.selections.all_adjusted(cx);
15427
15428        for selection in selections {
15429            let range = selection.range().sorted();
15430            let buffer_start_row = range.start.row;
15431
15432            if range.start.row != range.end.row {
15433                let mut found = false;
15434                for row in range.start.row..=range.end.row {
15435                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15436                        found = true;
15437                        to_fold.push(crease);
15438                    }
15439                }
15440                if found {
15441                    continue;
15442                }
15443            }
15444
15445            for row in (0..=range.start.row).rev() {
15446                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15447                    if crease.range().end.row >= buffer_start_row {
15448                        to_fold.push(crease);
15449                    } else {
15450                        break;
15451                    }
15452                }
15453            }
15454        }
15455
15456        self.fold_creases(to_fold, true, window, cx);
15457    }
15458
15459    pub fn fold_at(
15460        &mut self,
15461        buffer_row: MultiBufferRow,
15462        window: &mut Window,
15463        cx: &mut Context<Self>,
15464    ) {
15465        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15466
15467        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15468            let autoscroll = self
15469                .selections
15470                .all::<Point>(cx)
15471                .iter()
15472                .any(|selection| crease.range().overlaps(&selection.range()));
15473
15474            self.fold_creases(vec![crease], autoscroll, window, cx);
15475        }
15476    }
15477
15478    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15479        if self.is_singleton(cx) {
15480            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15481            let buffer = &display_map.buffer_snapshot;
15482            let selections = self.selections.all::<Point>(cx);
15483            let ranges = selections
15484                .iter()
15485                .map(|s| {
15486                    let range = s.display_range(&display_map).sorted();
15487                    let mut start = range.start.to_point(&display_map);
15488                    let mut end = range.end.to_point(&display_map);
15489                    start.column = 0;
15490                    end.column = buffer.line_len(MultiBufferRow(end.row));
15491                    start..end
15492                })
15493                .collect::<Vec<_>>();
15494
15495            self.unfold_ranges(&ranges, true, true, cx);
15496        } else {
15497            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15498            let buffer_ids = self
15499                .selections
15500                .disjoint_anchor_ranges()
15501                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15502                .collect::<HashSet<_>>();
15503            for buffer_id in buffer_ids {
15504                self.unfold_buffer(buffer_id, cx);
15505            }
15506        }
15507    }
15508
15509    pub fn unfold_recursive(
15510        &mut self,
15511        _: &UnfoldRecursive,
15512        _window: &mut Window,
15513        cx: &mut Context<Self>,
15514    ) {
15515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15516        let selections = self.selections.all::<Point>(cx);
15517        let ranges = selections
15518            .iter()
15519            .map(|s| {
15520                let mut range = s.display_range(&display_map).sorted();
15521                *range.start.column_mut() = 0;
15522                *range.end.column_mut() = display_map.line_len(range.end.row());
15523                let start = range.start.to_point(&display_map);
15524                let end = range.end.to_point(&display_map);
15525                start..end
15526            })
15527            .collect::<Vec<_>>();
15528
15529        self.unfold_ranges(&ranges, true, true, cx);
15530    }
15531
15532    pub fn unfold_at(
15533        &mut self,
15534        buffer_row: MultiBufferRow,
15535        _window: &mut Window,
15536        cx: &mut Context<Self>,
15537    ) {
15538        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15539
15540        let intersection_range = Point::new(buffer_row.0, 0)
15541            ..Point::new(
15542                buffer_row.0,
15543                display_map.buffer_snapshot.line_len(buffer_row),
15544            );
15545
15546        let autoscroll = self
15547            .selections
15548            .all::<Point>(cx)
15549            .iter()
15550            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15551
15552        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15553    }
15554
15555    pub fn unfold_all(
15556        &mut self,
15557        _: &actions::UnfoldAll,
15558        _window: &mut Window,
15559        cx: &mut Context<Self>,
15560    ) {
15561        if self.buffer.read(cx).is_singleton() {
15562            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15563            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15564        } else {
15565            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15566                editor
15567                    .update(cx, |editor, cx| {
15568                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15569                            editor.unfold_buffer(buffer_id, cx);
15570                        }
15571                    })
15572                    .ok();
15573            });
15574        }
15575    }
15576
15577    pub fn fold_selected_ranges(
15578        &mut self,
15579        _: &FoldSelectedRanges,
15580        window: &mut Window,
15581        cx: &mut Context<Self>,
15582    ) {
15583        let selections = self.selections.all_adjusted(cx);
15584        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15585        let ranges = selections
15586            .into_iter()
15587            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15588            .collect::<Vec<_>>();
15589        self.fold_creases(ranges, true, window, cx);
15590    }
15591
15592    pub fn fold_ranges<T: ToOffset + Clone>(
15593        &mut self,
15594        ranges: Vec<Range<T>>,
15595        auto_scroll: bool,
15596        window: &mut Window,
15597        cx: &mut Context<Self>,
15598    ) {
15599        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15600        let ranges = ranges
15601            .into_iter()
15602            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15603            .collect::<Vec<_>>();
15604        self.fold_creases(ranges, auto_scroll, window, cx);
15605    }
15606
15607    pub fn fold_creases<T: ToOffset + Clone>(
15608        &mut self,
15609        creases: Vec<Crease<T>>,
15610        auto_scroll: bool,
15611        _window: &mut Window,
15612        cx: &mut Context<Self>,
15613    ) {
15614        if creases.is_empty() {
15615            return;
15616        }
15617
15618        let mut buffers_affected = HashSet::default();
15619        let multi_buffer = self.buffer().read(cx);
15620        for crease in &creases {
15621            if let Some((_, buffer, _)) =
15622                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
15623            {
15624                buffers_affected.insert(buffer.read(cx).remote_id());
15625            };
15626        }
15627
15628        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
15629
15630        if auto_scroll {
15631            self.request_autoscroll(Autoscroll::fit(), cx);
15632        }
15633
15634        cx.notify();
15635
15636        self.scrollbar_marker_state.dirty = true;
15637        self.folds_did_change(cx);
15638    }
15639
15640    /// Removes any folds whose ranges intersect any of the given ranges.
15641    pub fn unfold_ranges<T: ToOffset + Clone>(
15642        &mut self,
15643        ranges: &[Range<T>],
15644        inclusive: bool,
15645        auto_scroll: bool,
15646        cx: &mut Context<Self>,
15647    ) {
15648        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15649            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
15650        });
15651        self.folds_did_change(cx);
15652    }
15653
15654    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15655        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
15656            return;
15657        }
15658        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15659        self.display_map.update(cx, |display_map, cx| {
15660            display_map.fold_buffers([buffer_id], cx)
15661        });
15662        cx.emit(EditorEvent::BufferFoldToggled {
15663            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
15664            folded: true,
15665        });
15666        cx.notify();
15667    }
15668
15669    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15670        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
15671            return;
15672        }
15673        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15674        self.display_map.update(cx, |display_map, cx| {
15675            display_map.unfold_buffers([buffer_id], cx);
15676        });
15677        cx.emit(EditorEvent::BufferFoldToggled {
15678            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
15679            folded: false,
15680        });
15681        cx.notify();
15682    }
15683
15684    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
15685        self.display_map.read(cx).is_buffer_folded(buffer)
15686    }
15687
15688    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
15689        self.display_map.read(cx).folded_buffers()
15690    }
15691
15692    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15693        self.display_map.update(cx, |display_map, cx| {
15694            display_map.disable_header_for_buffer(buffer_id, cx);
15695        });
15696        cx.notify();
15697    }
15698
15699    /// Removes any folds with the given ranges.
15700    pub fn remove_folds_with_type<T: ToOffset + Clone>(
15701        &mut self,
15702        ranges: &[Range<T>],
15703        type_id: TypeId,
15704        auto_scroll: bool,
15705        cx: &mut Context<Self>,
15706    ) {
15707        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15708            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
15709        });
15710        self.folds_did_change(cx);
15711    }
15712
15713    fn remove_folds_with<T: ToOffset + Clone>(
15714        &mut self,
15715        ranges: &[Range<T>],
15716        auto_scroll: bool,
15717        cx: &mut Context<Self>,
15718        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
15719    ) {
15720        if ranges.is_empty() {
15721            return;
15722        }
15723
15724        let mut buffers_affected = HashSet::default();
15725        let multi_buffer = self.buffer().read(cx);
15726        for range in ranges {
15727            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
15728                buffers_affected.insert(buffer.read(cx).remote_id());
15729            };
15730        }
15731
15732        self.display_map.update(cx, update);
15733
15734        if auto_scroll {
15735            self.request_autoscroll(Autoscroll::fit(), cx);
15736        }
15737
15738        cx.notify();
15739        self.scrollbar_marker_state.dirty = true;
15740        self.active_indent_guides_state.dirty = true;
15741    }
15742
15743    pub fn update_fold_widths(
15744        &mut self,
15745        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
15746        cx: &mut Context<Self>,
15747    ) -> bool {
15748        self.display_map
15749            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
15750    }
15751
15752    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
15753        self.display_map.read(cx).fold_placeholder.clone()
15754    }
15755
15756    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
15757        self.buffer.update(cx, |buffer, cx| {
15758            buffer.set_all_diff_hunks_expanded(cx);
15759        });
15760    }
15761
15762    pub fn expand_all_diff_hunks(
15763        &mut self,
15764        _: &ExpandAllDiffHunks,
15765        _window: &mut Window,
15766        cx: &mut Context<Self>,
15767    ) {
15768        self.buffer.update(cx, |buffer, cx| {
15769            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
15770        });
15771    }
15772
15773    pub fn toggle_selected_diff_hunks(
15774        &mut self,
15775        _: &ToggleSelectedDiffHunks,
15776        _window: &mut Window,
15777        cx: &mut Context<Self>,
15778    ) {
15779        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15780        self.toggle_diff_hunks_in_ranges(ranges, cx);
15781    }
15782
15783    pub fn diff_hunks_in_ranges<'a>(
15784        &'a self,
15785        ranges: &'a [Range<Anchor>],
15786        buffer: &'a MultiBufferSnapshot,
15787    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
15788        ranges.iter().flat_map(move |range| {
15789            let end_excerpt_id = range.end.excerpt_id;
15790            let range = range.to_point(buffer);
15791            let mut peek_end = range.end;
15792            if range.end.row < buffer.max_row().0 {
15793                peek_end = Point::new(range.end.row + 1, 0);
15794            }
15795            buffer
15796                .diff_hunks_in_range(range.start..peek_end)
15797                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
15798        })
15799    }
15800
15801    pub fn has_stageable_diff_hunks_in_ranges(
15802        &self,
15803        ranges: &[Range<Anchor>],
15804        snapshot: &MultiBufferSnapshot,
15805    ) -> bool {
15806        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
15807        hunks.any(|hunk| hunk.status().has_secondary_hunk())
15808    }
15809
15810    pub fn toggle_staged_selected_diff_hunks(
15811        &mut self,
15812        _: &::git::ToggleStaged,
15813        _: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) {
15816        let snapshot = self.buffer.read(cx).snapshot(cx);
15817        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15818        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
15819        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15820    }
15821
15822    pub fn set_render_diff_hunk_controls(
15823        &mut self,
15824        render_diff_hunk_controls: RenderDiffHunkControlsFn,
15825        cx: &mut Context<Self>,
15826    ) {
15827        self.render_diff_hunk_controls = render_diff_hunk_controls;
15828        cx.notify();
15829    }
15830
15831    pub fn stage_and_next(
15832        &mut self,
15833        _: &::git::StageAndNext,
15834        window: &mut Window,
15835        cx: &mut Context<Self>,
15836    ) {
15837        self.do_stage_or_unstage_and_next(true, window, cx);
15838    }
15839
15840    pub fn unstage_and_next(
15841        &mut self,
15842        _: &::git::UnstageAndNext,
15843        window: &mut Window,
15844        cx: &mut Context<Self>,
15845    ) {
15846        self.do_stage_or_unstage_and_next(false, window, cx);
15847    }
15848
15849    pub fn stage_or_unstage_diff_hunks(
15850        &mut self,
15851        stage: bool,
15852        ranges: Vec<Range<Anchor>>,
15853        cx: &mut Context<Self>,
15854    ) {
15855        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
15856        cx.spawn(async move |this, cx| {
15857            task.await?;
15858            this.update(cx, |this, cx| {
15859                let snapshot = this.buffer.read(cx).snapshot(cx);
15860                let chunk_by = this
15861                    .diff_hunks_in_ranges(&ranges, &snapshot)
15862                    .chunk_by(|hunk| hunk.buffer_id);
15863                for (buffer_id, hunks) in &chunk_by {
15864                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
15865                }
15866            })
15867        })
15868        .detach_and_log_err(cx);
15869    }
15870
15871    fn save_buffers_for_ranges_if_needed(
15872        &mut self,
15873        ranges: &[Range<Anchor>],
15874        cx: &mut Context<Editor>,
15875    ) -> Task<Result<()>> {
15876        let multibuffer = self.buffer.read(cx);
15877        let snapshot = multibuffer.read(cx);
15878        let buffer_ids: HashSet<_> = ranges
15879            .iter()
15880            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
15881            .collect();
15882        drop(snapshot);
15883
15884        let mut buffers = HashSet::default();
15885        for buffer_id in buffer_ids {
15886            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
15887                let buffer = buffer_entity.read(cx);
15888                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
15889                {
15890                    buffers.insert(buffer_entity);
15891                }
15892            }
15893        }
15894
15895        if let Some(project) = &self.project {
15896            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
15897        } else {
15898            Task::ready(Ok(()))
15899        }
15900    }
15901
15902    fn do_stage_or_unstage_and_next(
15903        &mut self,
15904        stage: bool,
15905        window: &mut Window,
15906        cx: &mut Context<Self>,
15907    ) {
15908        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
15909
15910        if ranges.iter().any(|range| range.start != range.end) {
15911            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15912            return;
15913        }
15914
15915        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15916        let snapshot = self.snapshot(window, cx);
15917        let position = self.selections.newest::<Point>(cx).head();
15918        let mut row = snapshot
15919            .buffer_snapshot
15920            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15921            .find(|hunk| hunk.row_range.start.0 > position.row)
15922            .map(|hunk| hunk.row_range.start);
15923
15924        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
15925        // Outside of the project diff editor, wrap around to the beginning.
15926        if !all_diff_hunks_expanded {
15927            row = row.or_else(|| {
15928                snapshot
15929                    .buffer_snapshot
15930                    .diff_hunks_in_range(Point::zero()..position)
15931                    .find(|hunk| hunk.row_range.end.0 < position.row)
15932                    .map(|hunk| hunk.row_range.start)
15933            });
15934        }
15935
15936        if let Some(row) = row {
15937            let destination = Point::new(row.0, 0);
15938            let autoscroll = Autoscroll::center();
15939
15940            self.unfold_ranges(&[destination..destination], false, false, cx);
15941            self.change_selections(Some(autoscroll), window, cx, |s| {
15942                s.select_ranges([destination..destination]);
15943            });
15944        }
15945    }
15946
15947    fn do_stage_or_unstage(
15948        &self,
15949        stage: bool,
15950        buffer_id: BufferId,
15951        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
15952        cx: &mut App,
15953    ) -> Option<()> {
15954        let project = self.project.as_ref()?;
15955        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
15956        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
15957        let buffer_snapshot = buffer.read(cx).snapshot();
15958        let file_exists = buffer_snapshot
15959            .file()
15960            .is_some_and(|file| file.disk_state().exists());
15961        diff.update(cx, |diff, cx| {
15962            diff.stage_or_unstage_hunks(
15963                stage,
15964                &hunks
15965                    .map(|hunk| buffer_diff::DiffHunk {
15966                        buffer_range: hunk.buffer_range,
15967                        diff_base_byte_range: hunk.diff_base_byte_range,
15968                        secondary_status: hunk.secondary_status,
15969                        range: Point::zero()..Point::zero(), // unused
15970                    })
15971                    .collect::<Vec<_>>(),
15972                &buffer_snapshot,
15973                file_exists,
15974                cx,
15975            )
15976        });
15977        None
15978    }
15979
15980    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
15981        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15982        self.buffer
15983            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
15984    }
15985
15986    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
15987        self.buffer.update(cx, |buffer, cx| {
15988            let ranges = vec![Anchor::min()..Anchor::max()];
15989            if !buffer.all_diff_hunks_expanded()
15990                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
15991            {
15992                buffer.collapse_diff_hunks(ranges, cx);
15993                true
15994            } else {
15995                false
15996            }
15997        })
15998    }
15999
16000    fn toggle_diff_hunks_in_ranges(
16001        &mut self,
16002        ranges: Vec<Range<Anchor>>,
16003        cx: &mut Context<Editor>,
16004    ) {
16005        self.buffer.update(cx, |buffer, cx| {
16006            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16007            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16008        })
16009    }
16010
16011    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16012        self.buffer.update(cx, |buffer, cx| {
16013            let snapshot = buffer.snapshot(cx);
16014            let excerpt_id = range.end.excerpt_id;
16015            let point_range = range.to_point(&snapshot);
16016            let expand = !buffer.single_hunk_is_expanded(range, cx);
16017            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16018        })
16019    }
16020
16021    pub(crate) fn apply_all_diff_hunks(
16022        &mut self,
16023        _: &ApplyAllDiffHunks,
16024        window: &mut Window,
16025        cx: &mut Context<Self>,
16026    ) {
16027        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16028
16029        let buffers = self.buffer.read(cx).all_buffers();
16030        for branch_buffer in buffers {
16031            branch_buffer.update(cx, |branch_buffer, cx| {
16032                branch_buffer.merge_into_base(Vec::new(), cx);
16033            });
16034        }
16035
16036        if let Some(project) = self.project.clone() {
16037            self.save(true, project, window, cx).detach_and_log_err(cx);
16038        }
16039    }
16040
16041    pub(crate) fn apply_selected_diff_hunks(
16042        &mut self,
16043        _: &ApplyDiffHunk,
16044        window: &mut Window,
16045        cx: &mut Context<Self>,
16046    ) {
16047        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16048        let snapshot = self.snapshot(window, cx);
16049        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16050        let mut ranges_by_buffer = HashMap::default();
16051        self.transact(window, cx, |editor, _window, cx| {
16052            for hunk in hunks {
16053                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16054                    ranges_by_buffer
16055                        .entry(buffer.clone())
16056                        .or_insert_with(Vec::new)
16057                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16058                }
16059            }
16060
16061            for (buffer, ranges) in ranges_by_buffer {
16062                buffer.update(cx, |buffer, cx| {
16063                    buffer.merge_into_base(ranges, cx);
16064                });
16065            }
16066        });
16067
16068        if let Some(project) = self.project.clone() {
16069            self.save(true, project, window, cx).detach_and_log_err(cx);
16070        }
16071    }
16072
16073    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16074        if hovered != self.gutter_hovered {
16075            self.gutter_hovered = hovered;
16076            cx.notify();
16077        }
16078    }
16079
16080    pub fn insert_blocks(
16081        &mut self,
16082        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16083        autoscroll: Option<Autoscroll>,
16084        cx: &mut Context<Self>,
16085    ) -> Vec<CustomBlockId> {
16086        let blocks = self
16087            .display_map
16088            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16089        if let Some(autoscroll) = autoscroll {
16090            self.request_autoscroll(autoscroll, cx);
16091        }
16092        cx.notify();
16093        blocks
16094    }
16095
16096    pub fn resize_blocks(
16097        &mut self,
16098        heights: HashMap<CustomBlockId, u32>,
16099        autoscroll: Option<Autoscroll>,
16100        cx: &mut Context<Self>,
16101    ) {
16102        self.display_map
16103            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16104        if let Some(autoscroll) = autoscroll {
16105            self.request_autoscroll(autoscroll, cx);
16106        }
16107        cx.notify();
16108    }
16109
16110    pub fn replace_blocks(
16111        &mut self,
16112        renderers: HashMap<CustomBlockId, RenderBlock>,
16113        autoscroll: Option<Autoscroll>,
16114        cx: &mut Context<Self>,
16115    ) {
16116        self.display_map
16117            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16118        if let Some(autoscroll) = autoscroll {
16119            self.request_autoscroll(autoscroll, cx);
16120        }
16121        cx.notify();
16122    }
16123
16124    pub fn remove_blocks(
16125        &mut self,
16126        block_ids: HashSet<CustomBlockId>,
16127        autoscroll: Option<Autoscroll>,
16128        cx: &mut Context<Self>,
16129    ) {
16130        self.display_map.update(cx, |display_map, cx| {
16131            display_map.remove_blocks(block_ids, cx)
16132        });
16133        if let Some(autoscroll) = autoscroll {
16134            self.request_autoscroll(autoscroll, cx);
16135        }
16136        cx.notify();
16137    }
16138
16139    pub fn row_for_block(
16140        &self,
16141        block_id: CustomBlockId,
16142        cx: &mut Context<Self>,
16143    ) -> Option<DisplayRow> {
16144        self.display_map
16145            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16146    }
16147
16148    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16149        self.focused_block = Some(focused_block);
16150    }
16151
16152    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16153        self.focused_block.take()
16154    }
16155
16156    pub fn insert_creases(
16157        &mut self,
16158        creases: impl IntoIterator<Item = Crease<Anchor>>,
16159        cx: &mut Context<Self>,
16160    ) -> Vec<CreaseId> {
16161        self.display_map
16162            .update(cx, |map, cx| map.insert_creases(creases, cx))
16163    }
16164
16165    pub fn remove_creases(
16166        &mut self,
16167        ids: impl IntoIterator<Item = CreaseId>,
16168        cx: &mut Context<Self>,
16169    ) {
16170        self.display_map
16171            .update(cx, |map, cx| map.remove_creases(ids, cx));
16172    }
16173
16174    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16175        self.display_map
16176            .update(cx, |map, cx| map.snapshot(cx))
16177            .longest_row()
16178    }
16179
16180    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16181        self.display_map
16182            .update(cx, |map, cx| map.snapshot(cx))
16183            .max_point()
16184    }
16185
16186    pub fn text(&self, cx: &App) -> String {
16187        self.buffer.read(cx).read(cx).text()
16188    }
16189
16190    pub fn is_empty(&self, cx: &App) -> bool {
16191        self.buffer.read(cx).read(cx).is_empty()
16192    }
16193
16194    pub fn text_option(&self, cx: &App) -> Option<String> {
16195        let text = self.text(cx);
16196        let text = text.trim();
16197
16198        if text.is_empty() {
16199            return None;
16200        }
16201
16202        Some(text.to_string())
16203    }
16204
16205    pub fn set_text(
16206        &mut self,
16207        text: impl Into<Arc<str>>,
16208        window: &mut Window,
16209        cx: &mut Context<Self>,
16210    ) {
16211        self.transact(window, cx, |this, _, cx| {
16212            this.buffer
16213                .read(cx)
16214                .as_singleton()
16215                .expect("you can only call set_text on editors for singleton buffers")
16216                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16217        });
16218    }
16219
16220    pub fn display_text(&self, cx: &mut App) -> String {
16221        self.display_map
16222            .update(cx, |map, cx| map.snapshot(cx))
16223            .text()
16224    }
16225
16226    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16227        let mut wrap_guides = smallvec::smallvec![];
16228
16229        if self.show_wrap_guides == Some(false) {
16230            return wrap_guides;
16231        }
16232
16233        let settings = self.buffer.read(cx).language_settings(cx);
16234        if settings.show_wrap_guides {
16235            match self.soft_wrap_mode(cx) {
16236                SoftWrap::Column(soft_wrap) => {
16237                    wrap_guides.push((soft_wrap as usize, true));
16238                }
16239                SoftWrap::Bounded(soft_wrap) => {
16240                    wrap_guides.push((soft_wrap as usize, true));
16241                }
16242                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16243            }
16244            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16245        }
16246
16247        wrap_guides
16248    }
16249
16250    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16251        let settings = self.buffer.read(cx).language_settings(cx);
16252        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16253        match mode {
16254            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16255                SoftWrap::None
16256            }
16257            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16258            language_settings::SoftWrap::PreferredLineLength => {
16259                SoftWrap::Column(settings.preferred_line_length)
16260            }
16261            language_settings::SoftWrap::Bounded => {
16262                SoftWrap::Bounded(settings.preferred_line_length)
16263            }
16264        }
16265    }
16266
16267    pub fn set_soft_wrap_mode(
16268        &mut self,
16269        mode: language_settings::SoftWrap,
16270
16271        cx: &mut Context<Self>,
16272    ) {
16273        self.soft_wrap_mode_override = Some(mode);
16274        cx.notify();
16275    }
16276
16277    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16278        self.hard_wrap = hard_wrap;
16279        cx.notify();
16280    }
16281
16282    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16283        self.text_style_refinement = Some(style);
16284    }
16285
16286    /// called by the Element so we know what style we were most recently rendered with.
16287    pub(crate) fn set_style(
16288        &mut self,
16289        style: EditorStyle,
16290        window: &mut Window,
16291        cx: &mut Context<Self>,
16292    ) {
16293        let rem_size = window.rem_size();
16294        self.display_map.update(cx, |map, cx| {
16295            map.set_font(
16296                style.text.font(),
16297                style.text.font_size.to_pixels(rem_size),
16298                cx,
16299            )
16300        });
16301        self.style = Some(style);
16302    }
16303
16304    pub fn style(&self) -> Option<&EditorStyle> {
16305        self.style.as_ref()
16306    }
16307
16308    // Called by the element. This method is not designed to be called outside of the editor
16309    // element's layout code because it does not notify when rewrapping is computed synchronously.
16310    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16311        self.display_map
16312            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16313    }
16314
16315    pub fn set_soft_wrap(&mut self) {
16316        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16317    }
16318
16319    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16320        if self.soft_wrap_mode_override.is_some() {
16321            self.soft_wrap_mode_override.take();
16322        } else {
16323            let soft_wrap = match self.soft_wrap_mode(cx) {
16324                SoftWrap::GitDiff => return,
16325                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16326                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16327                    language_settings::SoftWrap::None
16328                }
16329            };
16330            self.soft_wrap_mode_override = Some(soft_wrap);
16331        }
16332        cx.notify();
16333    }
16334
16335    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16336        let Some(workspace) = self.workspace() else {
16337            return;
16338        };
16339        let fs = workspace.read(cx).app_state().fs.clone();
16340        let current_show = TabBarSettings::get_global(cx).show;
16341        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16342            setting.show = Some(!current_show);
16343        });
16344    }
16345
16346    pub fn toggle_indent_guides(
16347        &mut self,
16348        _: &ToggleIndentGuides,
16349        _: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) {
16352        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16353            self.buffer
16354                .read(cx)
16355                .language_settings(cx)
16356                .indent_guides
16357                .enabled
16358        });
16359        self.show_indent_guides = Some(!currently_enabled);
16360        cx.notify();
16361    }
16362
16363    fn should_show_indent_guides(&self) -> Option<bool> {
16364        self.show_indent_guides
16365    }
16366
16367    pub fn toggle_line_numbers(
16368        &mut self,
16369        _: &ToggleLineNumbers,
16370        _: &mut Window,
16371        cx: &mut Context<Self>,
16372    ) {
16373        let mut editor_settings = EditorSettings::get_global(cx).clone();
16374        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16375        EditorSettings::override_global(editor_settings, cx);
16376    }
16377
16378    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16379        if let Some(show_line_numbers) = self.show_line_numbers {
16380            return show_line_numbers;
16381        }
16382        EditorSettings::get_global(cx).gutter.line_numbers
16383    }
16384
16385    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16386        self.use_relative_line_numbers
16387            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16388    }
16389
16390    pub fn toggle_relative_line_numbers(
16391        &mut self,
16392        _: &ToggleRelativeLineNumbers,
16393        _: &mut Window,
16394        cx: &mut Context<Self>,
16395    ) {
16396        let is_relative = self.should_use_relative_line_numbers(cx);
16397        self.set_relative_line_number(Some(!is_relative), cx)
16398    }
16399
16400    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16401        self.use_relative_line_numbers = is_relative;
16402        cx.notify();
16403    }
16404
16405    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16406        self.show_gutter = show_gutter;
16407        cx.notify();
16408    }
16409
16410    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16411        self.show_scrollbars = show_scrollbars;
16412        cx.notify();
16413    }
16414
16415    pub fn disable_scrolling(&mut self, cx: &mut Context<Self>) {
16416        self.disable_scrolling = true;
16417        cx.notify();
16418    }
16419
16420    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16421        self.show_line_numbers = Some(show_line_numbers);
16422        cx.notify();
16423    }
16424
16425    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16426        self.disable_expand_excerpt_buttons = true;
16427        cx.notify();
16428    }
16429
16430    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16431        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16432        cx.notify();
16433    }
16434
16435    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16436        self.show_code_actions = Some(show_code_actions);
16437        cx.notify();
16438    }
16439
16440    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16441        self.show_runnables = Some(show_runnables);
16442        cx.notify();
16443    }
16444
16445    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16446        self.show_breakpoints = Some(show_breakpoints);
16447        cx.notify();
16448    }
16449
16450    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16451        if self.display_map.read(cx).masked != masked {
16452            self.display_map.update(cx, |map, _| map.masked = masked);
16453        }
16454        cx.notify()
16455    }
16456
16457    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16458        self.show_wrap_guides = Some(show_wrap_guides);
16459        cx.notify();
16460    }
16461
16462    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16463        self.show_indent_guides = Some(show_indent_guides);
16464        cx.notify();
16465    }
16466
16467    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16468        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16469            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16470                if let Some(dir) = file.abs_path(cx).parent() {
16471                    return Some(dir.to_owned());
16472                }
16473            }
16474
16475            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16476                return Some(project_path.path.to_path_buf());
16477            }
16478        }
16479
16480        None
16481    }
16482
16483    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16484        self.active_excerpt(cx)?
16485            .1
16486            .read(cx)
16487            .file()
16488            .and_then(|f| f.as_local())
16489    }
16490
16491    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16492        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16493            let buffer = buffer.read(cx);
16494            if let Some(project_path) = buffer.project_path(cx) {
16495                let project = self.project.as_ref()?.read(cx);
16496                project.absolute_path(&project_path, cx)
16497            } else {
16498                buffer
16499                    .file()
16500                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16501            }
16502        })
16503    }
16504
16505    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16506        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16507            let project_path = buffer.read(cx).project_path(cx)?;
16508            let project = self.project.as_ref()?.read(cx);
16509            let entry = project.entry_for_path(&project_path, cx)?;
16510            let path = entry.path.to_path_buf();
16511            Some(path)
16512        })
16513    }
16514
16515    pub fn reveal_in_finder(
16516        &mut self,
16517        _: &RevealInFileManager,
16518        _window: &mut Window,
16519        cx: &mut Context<Self>,
16520    ) {
16521        if let Some(target) = self.target_file(cx) {
16522            cx.reveal_path(&target.abs_path(cx));
16523        }
16524    }
16525
16526    pub fn copy_path(
16527        &mut self,
16528        _: &zed_actions::workspace::CopyPath,
16529        _window: &mut Window,
16530        cx: &mut Context<Self>,
16531    ) {
16532        if let Some(path) = self.target_file_abs_path(cx) {
16533            if let Some(path) = path.to_str() {
16534                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16535            }
16536        }
16537    }
16538
16539    pub fn copy_relative_path(
16540        &mut self,
16541        _: &zed_actions::workspace::CopyRelativePath,
16542        _window: &mut Window,
16543        cx: &mut Context<Self>,
16544    ) {
16545        if let Some(path) = self.target_file_path(cx) {
16546            if let Some(path) = path.to_str() {
16547                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16548            }
16549        }
16550    }
16551
16552    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
16553        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
16554            buffer.read(cx).project_path(cx)
16555        } else {
16556            None
16557        }
16558    }
16559
16560    // Returns true if the editor handled a go-to-line request
16561    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
16562        maybe!({
16563            let breakpoint_store = self.breakpoint_store.as_ref()?;
16564
16565            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
16566            else {
16567                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16568                return None;
16569            };
16570
16571            let position = active_stack_frame.position;
16572            let buffer_id = position.buffer_id?;
16573            let snapshot = self
16574                .project
16575                .as_ref()?
16576                .read(cx)
16577                .buffer_for_id(buffer_id, cx)?
16578                .read(cx)
16579                .snapshot();
16580
16581            let mut handled = false;
16582            for (id, ExcerptRange { context, .. }) in
16583                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
16584            {
16585                if context.start.cmp(&position, &snapshot).is_ge()
16586                    || context.end.cmp(&position, &snapshot).is_lt()
16587                {
16588                    continue;
16589                }
16590                let snapshot = self.buffer.read(cx).snapshot(cx);
16591                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
16592
16593                handled = true;
16594                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16595                self.go_to_line::<DebugCurrentRowHighlight>(
16596                    multibuffer_anchor,
16597                    Some(cx.theme().colors().editor_debugger_active_line_background),
16598                    window,
16599                    cx,
16600                );
16601
16602                cx.notify();
16603            }
16604
16605            handled.then_some(())
16606        })
16607        .is_some()
16608    }
16609
16610    pub fn copy_file_name_without_extension(
16611        &mut self,
16612        _: &CopyFileNameWithoutExtension,
16613        _: &mut Window,
16614        cx: &mut Context<Self>,
16615    ) {
16616        if let Some(file) = self.target_file(cx) {
16617            if let Some(file_stem) = file.path().file_stem() {
16618                if let Some(name) = file_stem.to_str() {
16619                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16620                }
16621            }
16622        }
16623    }
16624
16625    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
16626        if let Some(file) = self.target_file(cx) {
16627            if let Some(file_name) = file.path().file_name() {
16628                if let Some(name) = file_name.to_str() {
16629                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16630                }
16631            }
16632        }
16633    }
16634
16635    pub fn toggle_git_blame(
16636        &mut self,
16637        _: &::git::Blame,
16638        window: &mut Window,
16639        cx: &mut Context<Self>,
16640    ) {
16641        self.show_git_blame_gutter = !self.show_git_blame_gutter;
16642
16643        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
16644            self.start_git_blame(true, window, cx);
16645        }
16646
16647        cx.notify();
16648    }
16649
16650    pub fn toggle_git_blame_inline(
16651        &mut self,
16652        _: &ToggleGitBlameInline,
16653        window: &mut Window,
16654        cx: &mut Context<Self>,
16655    ) {
16656        self.toggle_git_blame_inline_internal(true, window, cx);
16657        cx.notify();
16658    }
16659
16660    pub fn open_git_blame_commit(
16661        &mut self,
16662        _: &OpenGitBlameCommit,
16663        window: &mut Window,
16664        cx: &mut Context<Self>,
16665    ) {
16666        self.open_git_blame_commit_internal(window, cx);
16667    }
16668
16669    fn open_git_blame_commit_internal(
16670        &mut self,
16671        window: &mut Window,
16672        cx: &mut Context<Self>,
16673    ) -> Option<()> {
16674        let blame = self.blame.as_ref()?;
16675        let snapshot = self.snapshot(window, cx);
16676        let cursor = self.selections.newest::<Point>(cx).head();
16677        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
16678        let blame_entry = blame
16679            .update(cx, |blame, cx| {
16680                blame
16681                    .blame_for_rows(
16682                        &[RowInfo {
16683                            buffer_id: Some(buffer.remote_id()),
16684                            buffer_row: Some(point.row),
16685                            ..Default::default()
16686                        }],
16687                        cx,
16688                    )
16689                    .next()
16690            })
16691            .flatten()?;
16692        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
16693        let repo = blame.read(cx).repository(cx)?;
16694        let workspace = self.workspace()?.downgrade();
16695        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
16696        None
16697    }
16698
16699    pub fn git_blame_inline_enabled(&self) -> bool {
16700        self.git_blame_inline_enabled
16701    }
16702
16703    pub fn toggle_selection_menu(
16704        &mut self,
16705        _: &ToggleSelectionMenu,
16706        _: &mut Window,
16707        cx: &mut Context<Self>,
16708    ) {
16709        self.show_selection_menu = self
16710            .show_selection_menu
16711            .map(|show_selections_menu| !show_selections_menu)
16712            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
16713
16714        cx.notify();
16715    }
16716
16717    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
16718        self.show_selection_menu
16719            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
16720    }
16721
16722    fn start_git_blame(
16723        &mut self,
16724        user_triggered: bool,
16725        window: &mut Window,
16726        cx: &mut Context<Self>,
16727    ) {
16728        if let Some(project) = self.project.as_ref() {
16729            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
16730                return;
16731            };
16732
16733            if buffer.read(cx).file().is_none() {
16734                return;
16735            }
16736
16737            let focused = self.focus_handle(cx).contains_focused(window, cx);
16738
16739            let project = project.clone();
16740            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
16741            self.blame_subscription =
16742                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
16743            self.blame = Some(blame);
16744        }
16745    }
16746
16747    fn toggle_git_blame_inline_internal(
16748        &mut self,
16749        user_triggered: bool,
16750        window: &mut Window,
16751        cx: &mut Context<Self>,
16752    ) {
16753        if self.git_blame_inline_enabled {
16754            self.git_blame_inline_enabled = false;
16755            self.show_git_blame_inline = false;
16756            self.show_git_blame_inline_delay_task.take();
16757        } else {
16758            self.git_blame_inline_enabled = true;
16759            self.start_git_blame_inline(user_triggered, window, cx);
16760        }
16761
16762        cx.notify();
16763    }
16764
16765    fn start_git_blame_inline(
16766        &mut self,
16767        user_triggered: bool,
16768        window: &mut Window,
16769        cx: &mut Context<Self>,
16770    ) {
16771        self.start_git_blame(user_triggered, window, cx);
16772
16773        if ProjectSettings::get_global(cx)
16774            .git
16775            .inline_blame_delay()
16776            .is_some()
16777        {
16778            self.start_inline_blame_timer(window, cx);
16779        } else {
16780            self.show_git_blame_inline = true
16781        }
16782    }
16783
16784    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
16785        self.blame.as_ref()
16786    }
16787
16788    pub fn show_git_blame_gutter(&self) -> bool {
16789        self.show_git_blame_gutter
16790    }
16791
16792    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
16793        self.show_git_blame_gutter && self.has_blame_entries(cx)
16794    }
16795
16796    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
16797        self.show_git_blame_inline
16798            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
16799            && !self.newest_selection_head_on_empty_line(cx)
16800            && self.has_blame_entries(cx)
16801    }
16802
16803    fn has_blame_entries(&self, cx: &App) -> bool {
16804        self.blame()
16805            .map_or(false, |blame| blame.read(cx).has_generated_entries())
16806    }
16807
16808    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
16809        let cursor_anchor = self.selections.newest_anchor().head();
16810
16811        let snapshot = self.buffer.read(cx).snapshot(cx);
16812        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
16813
16814        snapshot.line_len(buffer_row) == 0
16815    }
16816
16817    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
16818        let buffer_and_selection = maybe!({
16819            let selection = self.selections.newest::<Point>(cx);
16820            let selection_range = selection.range();
16821
16822            let multi_buffer = self.buffer().read(cx);
16823            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16824            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
16825
16826            let (buffer, range, _) = if selection.reversed {
16827                buffer_ranges.first()
16828            } else {
16829                buffer_ranges.last()
16830            }?;
16831
16832            let selection = text::ToPoint::to_point(&range.start, &buffer).row
16833                ..text::ToPoint::to_point(&range.end, &buffer).row;
16834            Some((
16835                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
16836                selection,
16837            ))
16838        });
16839
16840        let Some((buffer, selection)) = buffer_and_selection else {
16841            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
16842        };
16843
16844        let Some(project) = self.project.as_ref() else {
16845            return Task::ready(Err(anyhow!("editor does not have project")));
16846        };
16847
16848        project.update(cx, |project, cx| {
16849            project.get_permalink_to_line(&buffer, selection, cx)
16850        })
16851    }
16852
16853    pub fn copy_permalink_to_line(
16854        &mut self,
16855        _: &CopyPermalinkToLine,
16856        window: &mut Window,
16857        cx: &mut Context<Self>,
16858    ) {
16859        let permalink_task = self.get_permalink_to_line(cx);
16860        let workspace = self.workspace();
16861
16862        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16863            Ok(permalink) => {
16864                cx.update(|_, cx| {
16865                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
16866                })
16867                .ok();
16868            }
16869            Err(err) => {
16870                let message = format!("Failed to copy permalink: {err}");
16871
16872                Err::<(), anyhow::Error>(err).log_err();
16873
16874                if let Some(workspace) = workspace {
16875                    workspace
16876                        .update_in(cx, |workspace, _, cx| {
16877                            struct CopyPermalinkToLine;
16878
16879                            workspace.show_toast(
16880                                Toast::new(
16881                                    NotificationId::unique::<CopyPermalinkToLine>(),
16882                                    message,
16883                                ),
16884                                cx,
16885                            )
16886                        })
16887                        .ok();
16888                }
16889            }
16890        })
16891        .detach();
16892    }
16893
16894    pub fn copy_file_location(
16895        &mut self,
16896        _: &CopyFileLocation,
16897        _: &mut Window,
16898        cx: &mut Context<Self>,
16899    ) {
16900        let selection = self.selections.newest::<Point>(cx).start.row + 1;
16901        if let Some(file) = self.target_file(cx) {
16902            if let Some(path) = file.path().to_str() {
16903                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
16904            }
16905        }
16906    }
16907
16908    pub fn open_permalink_to_line(
16909        &mut self,
16910        _: &OpenPermalinkToLine,
16911        window: &mut Window,
16912        cx: &mut Context<Self>,
16913    ) {
16914        let permalink_task = self.get_permalink_to_line(cx);
16915        let workspace = self.workspace();
16916
16917        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16918            Ok(permalink) => {
16919                cx.update(|_, cx| {
16920                    cx.open_url(permalink.as_ref());
16921                })
16922                .ok();
16923            }
16924            Err(err) => {
16925                let message = format!("Failed to open permalink: {err}");
16926
16927                Err::<(), anyhow::Error>(err).log_err();
16928
16929                if let Some(workspace) = workspace {
16930                    workspace
16931                        .update(cx, |workspace, cx| {
16932                            struct OpenPermalinkToLine;
16933
16934                            workspace.show_toast(
16935                                Toast::new(
16936                                    NotificationId::unique::<OpenPermalinkToLine>(),
16937                                    message,
16938                                ),
16939                                cx,
16940                            )
16941                        })
16942                        .ok();
16943                }
16944            }
16945        })
16946        .detach();
16947    }
16948
16949    pub fn insert_uuid_v4(
16950        &mut self,
16951        _: &InsertUuidV4,
16952        window: &mut Window,
16953        cx: &mut Context<Self>,
16954    ) {
16955        self.insert_uuid(UuidVersion::V4, window, cx);
16956    }
16957
16958    pub fn insert_uuid_v7(
16959        &mut self,
16960        _: &InsertUuidV7,
16961        window: &mut Window,
16962        cx: &mut Context<Self>,
16963    ) {
16964        self.insert_uuid(UuidVersion::V7, window, cx);
16965    }
16966
16967    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
16968        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16969        self.transact(window, cx, |this, window, cx| {
16970            let edits = this
16971                .selections
16972                .all::<Point>(cx)
16973                .into_iter()
16974                .map(|selection| {
16975                    let uuid = match version {
16976                        UuidVersion::V4 => uuid::Uuid::new_v4(),
16977                        UuidVersion::V7 => uuid::Uuid::now_v7(),
16978                    };
16979
16980                    (selection.range(), uuid.to_string())
16981                });
16982            this.edit(edits, cx);
16983            this.refresh_inline_completion(true, false, window, cx);
16984        });
16985    }
16986
16987    pub fn open_selections_in_multibuffer(
16988        &mut self,
16989        _: &OpenSelectionsInMultibuffer,
16990        window: &mut Window,
16991        cx: &mut Context<Self>,
16992    ) {
16993        let multibuffer = self.buffer.read(cx);
16994
16995        let Some(buffer) = multibuffer.as_singleton() else {
16996            return;
16997        };
16998
16999        let Some(workspace) = self.workspace() else {
17000            return;
17001        };
17002
17003        let locations = self
17004            .selections
17005            .disjoint_anchors()
17006            .iter()
17007            .map(|range| Location {
17008                buffer: buffer.clone(),
17009                range: range.start.text_anchor..range.end.text_anchor,
17010            })
17011            .collect::<Vec<_>>();
17012
17013        let title = multibuffer.title(cx).to_string();
17014
17015        cx.spawn_in(window, async move |_, cx| {
17016            workspace.update_in(cx, |workspace, window, cx| {
17017                Self::open_locations_in_multibuffer(
17018                    workspace,
17019                    locations,
17020                    format!("Selections for '{title}'"),
17021                    false,
17022                    MultibufferSelectionMode::All,
17023                    window,
17024                    cx,
17025                );
17026            })
17027        })
17028        .detach();
17029    }
17030
17031    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17032    /// last highlight added will be used.
17033    ///
17034    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17035    pub fn highlight_rows<T: 'static>(
17036        &mut self,
17037        range: Range<Anchor>,
17038        color: Hsla,
17039        options: RowHighlightOptions,
17040        cx: &mut Context<Self>,
17041    ) {
17042        let snapshot = self.buffer().read(cx).snapshot(cx);
17043        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17044        let ix = row_highlights.binary_search_by(|highlight| {
17045            Ordering::Equal
17046                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17047                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17048        });
17049
17050        if let Err(mut ix) = ix {
17051            let index = post_inc(&mut self.highlight_order);
17052
17053            // If this range intersects with the preceding highlight, then merge it with
17054            // the preceding highlight. Otherwise insert a new highlight.
17055            let mut merged = false;
17056            if ix > 0 {
17057                let prev_highlight = &mut row_highlights[ix - 1];
17058                if prev_highlight
17059                    .range
17060                    .end
17061                    .cmp(&range.start, &snapshot)
17062                    .is_ge()
17063                {
17064                    ix -= 1;
17065                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17066                        prev_highlight.range.end = range.end;
17067                    }
17068                    merged = true;
17069                    prev_highlight.index = index;
17070                    prev_highlight.color = color;
17071                    prev_highlight.options = options;
17072                }
17073            }
17074
17075            if !merged {
17076                row_highlights.insert(
17077                    ix,
17078                    RowHighlight {
17079                        range: range.clone(),
17080                        index,
17081                        color,
17082                        options,
17083                        type_id: TypeId::of::<T>(),
17084                    },
17085                );
17086            }
17087
17088            // If any of the following highlights intersect with this one, merge them.
17089            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17090                let highlight = &row_highlights[ix];
17091                if next_highlight
17092                    .range
17093                    .start
17094                    .cmp(&highlight.range.end, &snapshot)
17095                    .is_le()
17096                {
17097                    if next_highlight
17098                        .range
17099                        .end
17100                        .cmp(&highlight.range.end, &snapshot)
17101                        .is_gt()
17102                    {
17103                        row_highlights[ix].range.end = next_highlight.range.end;
17104                    }
17105                    row_highlights.remove(ix + 1);
17106                } else {
17107                    break;
17108                }
17109            }
17110        }
17111    }
17112
17113    /// Remove any highlighted row ranges of the given type that intersect the
17114    /// given ranges.
17115    pub fn remove_highlighted_rows<T: 'static>(
17116        &mut self,
17117        ranges_to_remove: Vec<Range<Anchor>>,
17118        cx: &mut Context<Self>,
17119    ) {
17120        let snapshot = self.buffer().read(cx).snapshot(cx);
17121        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17122        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17123        row_highlights.retain(|highlight| {
17124            while let Some(range_to_remove) = ranges_to_remove.peek() {
17125                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17126                    Ordering::Less | Ordering::Equal => {
17127                        ranges_to_remove.next();
17128                    }
17129                    Ordering::Greater => {
17130                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17131                            Ordering::Less | Ordering::Equal => {
17132                                return false;
17133                            }
17134                            Ordering::Greater => break,
17135                        }
17136                    }
17137                }
17138            }
17139
17140            true
17141        })
17142    }
17143
17144    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17145    pub fn clear_row_highlights<T: 'static>(&mut self) {
17146        self.highlighted_rows.remove(&TypeId::of::<T>());
17147    }
17148
17149    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17150    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17151        self.highlighted_rows
17152            .get(&TypeId::of::<T>())
17153            .map_or(&[] as &[_], |vec| vec.as_slice())
17154            .iter()
17155            .map(|highlight| (highlight.range.clone(), highlight.color))
17156    }
17157
17158    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17159    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17160    /// Allows to ignore certain kinds of highlights.
17161    pub fn highlighted_display_rows(
17162        &self,
17163        window: &mut Window,
17164        cx: &mut App,
17165    ) -> BTreeMap<DisplayRow, LineHighlight> {
17166        let snapshot = self.snapshot(window, cx);
17167        let mut used_highlight_orders = HashMap::default();
17168        self.highlighted_rows
17169            .iter()
17170            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17171            .fold(
17172                BTreeMap::<DisplayRow, LineHighlight>::new(),
17173                |mut unique_rows, highlight| {
17174                    let start = highlight.range.start.to_display_point(&snapshot);
17175                    let end = highlight.range.end.to_display_point(&snapshot);
17176                    let start_row = start.row().0;
17177                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17178                        && end.column() == 0
17179                    {
17180                        end.row().0.saturating_sub(1)
17181                    } else {
17182                        end.row().0
17183                    };
17184                    for row in start_row..=end_row {
17185                        let used_index =
17186                            used_highlight_orders.entry(row).or_insert(highlight.index);
17187                        if highlight.index >= *used_index {
17188                            *used_index = highlight.index;
17189                            unique_rows.insert(
17190                                DisplayRow(row),
17191                                LineHighlight {
17192                                    include_gutter: highlight.options.include_gutter,
17193                                    border: None,
17194                                    background: highlight.color.into(),
17195                                    type_id: Some(highlight.type_id),
17196                                },
17197                            );
17198                        }
17199                    }
17200                    unique_rows
17201                },
17202            )
17203    }
17204
17205    pub fn highlighted_display_row_for_autoscroll(
17206        &self,
17207        snapshot: &DisplaySnapshot,
17208    ) -> Option<DisplayRow> {
17209        self.highlighted_rows
17210            .values()
17211            .flat_map(|highlighted_rows| highlighted_rows.iter())
17212            .filter_map(|highlight| {
17213                if highlight.options.autoscroll {
17214                    Some(highlight.range.start.to_display_point(snapshot).row())
17215                } else {
17216                    None
17217                }
17218            })
17219            .min()
17220    }
17221
17222    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17223        self.highlight_background::<SearchWithinRange>(
17224            ranges,
17225            |colors| colors.editor_document_highlight_read_background,
17226            cx,
17227        )
17228    }
17229
17230    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17231        self.breadcrumb_header = Some(new_header);
17232    }
17233
17234    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17235        self.clear_background_highlights::<SearchWithinRange>(cx);
17236    }
17237
17238    pub fn highlight_background<T: 'static>(
17239        &mut self,
17240        ranges: &[Range<Anchor>],
17241        color_fetcher: fn(&ThemeColors) -> Hsla,
17242        cx: &mut Context<Self>,
17243    ) {
17244        self.background_highlights
17245            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17246        self.scrollbar_marker_state.dirty = true;
17247        cx.notify();
17248    }
17249
17250    pub fn clear_background_highlights<T: 'static>(
17251        &mut self,
17252        cx: &mut Context<Self>,
17253    ) -> Option<BackgroundHighlight> {
17254        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17255        if !text_highlights.1.is_empty() {
17256            self.scrollbar_marker_state.dirty = true;
17257            cx.notify();
17258        }
17259        Some(text_highlights)
17260    }
17261
17262    pub fn highlight_gutter<T: 'static>(
17263        &mut self,
17264        ranges: &[Range<Anchor>],
17265        color_fetcher: fn(&App) -> Hsla,
17266        cx: &mut Context<Self>,
17267    ) {
17268        self.gutter_highlights
17269            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17270        cx.notify();
17271    }
17272
17273    pub fn clear_gutter_highlights<T: 'static>(
17274        &mut self,
17275        cx: &mut Context<Self>,
17276    ) -> Option<GutterHighlight> {
17277        cx.notify();
17278        self.gutter_highlights.remove(&TypeId::of::<T>())
17279    }
17280
17281    #[cfg(feature = "test-support")]
17282    pub fn all_text_background_highlights(
17283        &self,
17284        window: &mut Window,
17285        cx: &mut Context<Self>,
17286    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17287        let snapshot = self.snapshot(window, cx);
17288        let buffer = &snapshot.buffer_snapshot;
17289        let start = buffer.anchor_before(0);
17290        let end = buffer.anchor_after(buffer.len());
17291        let theme = cx.theme().colors();
17292        self.background_highlights_in_range(start..end, &snapshot, theme)
17293    }
17294
17295    #[cfg(feature = "test-support")]
17296    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17297        let snapshot = self.buffer().read(cx).snapshot(cx);
17298
17299        let highlights = self
17300            .background_highlights
17301            .get(&TypeId::of::<items::BufferSearchHighlights>());
17302
17303        if let Some((_color, ranges)) = highlights {
17304            ranges
17305                .iter()
17306                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17307                .collect_vec()
17308        } else {
17309            vec![]
17310        }
17311    }
17312
17313    fn document_highlights_for_position<'a>(
17314        &'a self,
17315        position: Anchor,
17316        buffer: &'a MultiBufferSnapshot,
17317    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17318        let read_highlights = self
17319            .background_highlights
17320            .get(&TypeId::of::<DocumentHighlightRead>())
17321            .map(|h| &h.1);
17322        let write_highlights = self
17323            .background_highlights
17324            .get(&TypeId::of::<DocumentHighlightWrite>())
17325            .map(|h| &h.1);
17326        let left_position = position.bias_left(buffer);
17327        let right_position = position.bias_right(buffer);
17328        read_highlights
17329            .into_iter()
17330            .chain(write_highlights)
17331            .flat_map(move |ranges| {
17332                let start_ix = match ranges.binary_search_by(|probe| {
17333                    let cmp = probe.end.cmp(&left_position, buffer);
17334                    if cmp.is_ge() {
17335                        Ordering::Greater
17336                    } else {
17337                        Ordering::Less
17338                    }
17339                }) {
17340                    Ok(i) | Err(i) => i,
17341                };
17342
17343                ranges[start_ix..]
17344                    .iter()
17345                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17346            })
17347    }
17348
17349    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17350        self.background_highlights
17351            .get(&TypeId::of::<T>())
17352            .map_or(false, |(_, highlights)| !highlights.is_empty())
17353    }
17354
17355    pub fn background_highlights_in_range(
17356        &self,
17357        search_range: Range<Anchor>,
17358        display_snapshot: &DisplaySnapshot,
17359        theme: &ThemeColors,
17360    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17361        let mut results = Vec::new();
17362        for (color_fetcher, ranges) in self.background_highlights.values() {
17363            let color = color_fetcher(theme);
17364            let start_ix = match ranges.binary_search_by(|probe| {
17365                let cmp = probe
17366                    .end
17367                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17368                if cmp.is_gt() {
17369                    Ordering::Greater
17370                } else {
17371                    Ordering::Less
17372                }
17373            }) {
17374                Ok(i) | Err(i) => i,
17375            };
17376            for range in &ranges[start_ix..] {
17377                if range
17378                    .start
17379                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17380                    .is_ge()
17381                {
17382                    break;
17383                }
17384
17385                let start = range.start.to_display_point(display_snapshot);
17386                let end = range.end.to_display_point(display_snapshot);
17387                results.push((start..end, color))
17388            }
17389        }
17390        results
17391    }
17392
17393    pub fn background_highlight_row_ranges<T: 'static>(
17394        &self,
17395        search_range: Range<Anchor>,
17396        display_snapshot: &DisplaySnapshot,
17397        count: usize,
17398    ) -> Vec<RangeInclusive<DisplayPoint>> {
17399        let mut results = Vec::new();
17400        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17401            return vec![];
17402        };
17403
17404        let start_ix = match ranges.binary_search_by(|probe| {
17405            let cmp = probe
17406                .end
17407                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17408            if cmp.is_gt() {
17409                Ordering::Greater
17410            } else {
17411                Ordering::Less
17412            }
17413        }) {
17414            Ok(i) | Err(i) => i,
17415        };
17416        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17417            if let (Some(start_display), Some(end_display)) = (start, end) {
17418                results.push(
17419                    start_display.to_display_point(display_snapshot)
17420                        ..=end_display.to_display_point(display_snapshot),
17421                );
17422            }
17423        };
17424        let mut start_row: Option<Point> = None;
17425        let mut end_row: Option<Point> = None;
17426        if ranges.len() > count {
17427            return Vec::new();
17428        }
17429        for range in &ranges[start_ix..] {
17430            if range
17431                .start
17432                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17433                .is_ge()
17434            {
17435                break;
17436            }
17437            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17438            if let Some(current_row) = &end_row {
17439                if end.row == current_row.row {
17440                    continue;
17441                }
17442            }
17443            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17444            if start_row.is_none() {
17445                assert_eq!(end_row, None);
17446                start_row = Some(start);
17447                end_row = Some(end);
17448                continue;
17449            }
17450            if let Some(current_end) = end_row.as_mut() {
17451                if start.row > current_end.row + 1 {
17452                    push_region(start_row, end_row);
17453                    start_row = Some(start);
17454                    end_row = Some(end);
17455                } else {
17456                    // Merge two hunks.
17457                    *current_end = end;
17458                }
17459            } else {
17460                unreachable!();
17461            }
17462        }
17463        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17464        push_region(start_row, end_row);
17465        results
17466    }
17467
17468    pub fn gutter_highlights_in_range(
17469        &self,
17470        search_range: Range<Anchor>,
17471        display_snapshot: &DisplaySnapshot,
17472        cx: &App,
17473    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17474        let mut results = Vec::new();
17475        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17476            let color = color_fetcher(cx);
17477            let start_ix = match ranges.binary_search_by(|probe| {
17478                let cmp = probe
17479                    .end
17480                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17481                if cmp.is_gt() {
17482                    Ordering::Greater
17483                } else {
17484                    Ordering::Less
17485                }
17486            }) {
17487                Ok(i) | Err(i) => i,
17488            };
17489            for range in &ranges[start_ix..] {
17490                if range
17491                    .start
17492                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17493                    .is_ge()
17494                {
17495                    break;
17496                }
17497
17498                let start = range.start.to_display_point(display_snapshot);
17499                let end = range.end.to_display_point(display_snapshot);
17500                results.push((start..end, color))
17501            }
17502        }
17503        results
17504    }
17505
17506    /// Get the text ranges corresponding to the redaction query
17507    pub fn redacted_ranges(
17508        &self,
17509        search_range: Range<Anchor>,
17510        display_snapshot: &DisplaySnapshot,
17511        cx: &App,
17512    ) -> Vec<Range<DisplayPoint>> {
17513        display_snapshot
17514            .buffer_snapshot
17515            .redacted_ranges(search_range, |file| {
17516                if let Some(file) = file {
17517                    file.is_private()
17518                        && EditorSettings::get(
17519                            Some(SettingsLocation {
17520                                worktree_id: file.worktree_id(cx),
17521                                path: file.path().as_ref(),
17522                            }),
17523                            cx,
17524                        )
17525                        .redact_private_values
17526                } else {
17527                    false
17528                }
17529            })
17530            .map(|range| {
17531                range.start.to_display_point(display_snapshot)
17532                    ..range.end.to_display_point(display_snapshot)
17533            })
17534            .collect()
17535    }
17536
17537    pub fn highlight_text<T: 'static>(
17538        &mut self,
17539        ranges: Vec<Range<Anchor>>,
17540        style: HighlightStyle,
17541        cx: &mut Context<Self>,
17542    ) {
17543        self.display_map.update(cx, |map, _| {
17544            map.highlight_text(TypeId::of::<T>(), ranges, style)
17545        });
17546        cx.notify();
17547    }
17548
17549    pub(crate) fn highlight_inlays<T: 'static>(
17550        &mut self,
17551        highlights: Vec<InlayHighlight>,
17552        style: HighlightStyle,
17553        cx: &mut Context<Self>,
17554    ) {
17555        self.display_map.update(cx, |map, _| {
17556            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
17557        });
17558        cx.notify();
17559    }
17560
17561    pub fn text_highlights<'a, T: 'static>(
17562        &'a self,
17563        cx: &'a App,
17564    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
17565        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
17566    }
17567
17568    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
17569        let cleared = self
17570            .display_map
17571            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
17572        if cleared {
17573            cx.notify();
17574        }
17575    }
17576
17577    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
17578        (self.read_only(cx) || self.blink_manager.read(cx).visible())
17579            && self.focus_handle.is_focused(window)
17580    }
17581
17582    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
17583        self.show_cursor_when_unfocused = is_enabled;
17584        cx.notify();
17585    }
17586
17587    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
17588        cx.notify();
17589    }
17590
17591    fn on_debug_session_event(
17592        &mut self,
17593        _session: Entity<Session>,
17594        event: &SessionEvent,
17595        cx: &mut Context<Self>,
17596    ) {
17597        match event {
17598            SessionEvent::InvalidateInlineValue => {
17599                self.refresh_inline_values(cx);
17600            }
17601            _ => {}
17602        }
17603    }
17604
17605    fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
17606        let Some(project) = self.project.clone() else {
17607            return;
17608        };
17609        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
17610            return;
17611        };
17612        if !self.inline_value_cache.enabled {
17613            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
17614            self.splice_inlays(&inlays, Vec::new(), cx);
17615            return;
17616        }
17617
17618        let current_execution_position = self
17619            .highlighted_rows
17620            .get(&TypeId::of::<DebugCurrentRowHighlight>())
17621            .and_then(|lines| lines.last().map(|line| line.range.start));
17622
17623        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
17624            let snapshot = editor
17625                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17626                .ok()?;
17627
17628            let inline_values = editor
17629                .update(cx, |_, cx| {
17630                    let Some(current_execution_position) = current_execution_position else {
17631                        return Some(Task::ready(Ok(Vec::new())));
17632                    };
17633
17634                    // todo(debugger) when introducing multi buffer inline values check execution position's buffer id to make sure the text
17635                    // anchor is in the same buffer
17636                    let range =
17637                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
17638                    project.inline_values(buffer, range, cx)
17639                })
17640                .ok()
17641                .flatten()?
17642                .await
17643                .context("refreshing debugger inlays")
17644                .log_err()?;
17645
17646            let (excerpt_id, buffer_id) = snapshot
17647                .excerpts()
17648                .next()
17649                .map(|excerpt| (excerpt.0, excerpt.1.remote_id()))?;
17650            editor
17651                .update(cx, |editor, cx| {
17652                    let new_inlays = inline_values
17653                        .into_iter()
17654                        .map(|debugger_value| {
17655                            Inlay::debugger_hint(
17656                                post_inc(&mut editor.next_inlay_id),
17657                                Anchor::in_buffer(excerpt_id, buffer_id, debugger_value.position),
17658                                debugger_value.text(),
17659                            )
17660                        })
17661                        .collect::<Vec<_>>();
17662                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
17663                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
17664
17665                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
17666                })
17667                .ok()?;
17668            Some(())
17669        });
17670    }
17671
17672    fn on_buffer_event(
17673        &mut self,
17674        multibuffer: &Entity<MultiBuffer>,
17675        event: &multi_buffer::Event,
17676        window: &mut Window,
17677        cx: &mut Context<Self>,
17678    ) {
17679        match event {
17680            multi_buffer::Event::Edited {
17681                singleton_buffer_edited,
17682                edited_buffer: buffer_edited,
17683            } => {
17684                self.scrollbar_marker_state.dirty = true;
17685                self.active_indent_guides_state.dirty = true;
17686                self.refresh_active_diagnostics(cx);
17687                self.refresh_code_actions(window, cx);
17688                if self.has_active_inline_completion() {
17689                    self.update_visible_inline_completion(window, cx);
17690                }
17691                if let Some(buffer) = buffer_edited {
17692                    let buffer_id = buffer.read(cx).remote_id();
17693                    if !self.registered_buffers.contains_key(&buffer_id) {
17694                        if let Some(project) = self.project.as_ref() {
17695                            project.update(cx, |project, cx| {
17696                                self.registered_buffers.insert(
17697                                    buffer_id,
17698                                    project.register_buffer_with_language_servers(&buffer, cx),
17699                                );
17700                            })
17701                        }
17702                    }
17703                }
17704                cx.emit(EditorEvent::BufferEdited);
17705                cx.emit(SearchEvent::MatchesInvalidated);
17706                if *singleton_buffer_edited {
17707                    if let Some(project) = &self.project {
17708                        #[allow(clippy::mutable_key_type)]
17709                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
17710                            multibuffer
17711                                .all_buffers()
17712                                .into_iter()
17713                                .filter_map(|buffer| {
17714                                    buffer.update(cx, |buffer, cx| {
17715                                        let language = buffer.language()?;
17716                                        let should_discard = project.update(cx, |project, cx| {
17717                                            project.is_local()
17718                                                && !project.has_language_servers_for(buffer, cx)
17719                                        });
17720                                        should_discard.not().then_some(language.clone())
17721                                    })
17722                                })
17723                                .collect::<HashSet<_>>()
17724                        });
17725                        if !languages_affected.is_empty() {
17726                            self.refresh_inlay_hints(
17727                                InlayHintRefreshReason::BufferEdited(languages_affected),
17728                                cx,
17729                            );
17730                        }
17731                    }
17732                }
17733
17734                let Some(project) = &self.project else { return };
17735                let (telemetry, is_via_ssh) = {
17736                    let project = project.read(cx);
17737                    let telemetry = project.client().telemetry().clone();
17738                    let is_via_ssh = project.is_via_ssh();
17739                    (telemetry, is_via_ssh)
17740                };
17741                refresh_linked_ranges(self, window, cx);
17742                telemetry.log_edit_event("editor", is_via_ssh);
17743            }
17744            multi_buffer::Event::ExcerptsAdded {
17745                buffer,
17746                predecessor,
17747                excerpts,
17748            } => {
17749                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17750                let buffer_id = buffer.read(cx).remote_id();
17751                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
17752                    if let Some(project) = &self.project {
17753                        get_uncommitted_diff_for_buffer(
17754                            project,
17755                            [buffer.clone()],
17756                            self.buffer.clone(),
17757                            cx,
17758                        )
17759                        .detach();
17760                    }
17761                }
17762                cx.emit(EditorEvent::ExcerptsAdded {
17763                    buffer: buffer.clone(),
17764                    predecessor: *predecessor,
17765                    excerpts: excerpts.clone(),
17766                });
17767                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17768            }
17769            multi_buffer::Event::ExcerptsRemoved {
17770                ids,
17771                removed_buffer_ids,
17772            } => {
17773                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
17774                let buffer = self.buffer.read(cx);
17775                self.registered_buffers
17776                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
17777                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17778                cx.emit(EditorEvent::ExcerptsRemoved {
17779                    ids: ids.clone(),
17780                    removed_buffer_ids: removed_buffer_ids.clone(),
17781                })
17782            }
17783            multi_buffer::Event::ExcerptsEdited {
17784                excerpt_ids,
17785                buffer_ids,
17786            } => {
17787                self.display_map.update(cx, |map, cx| {
17788                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
17789                });
17790                cx.emit(EditorEvent::ExcerptsEdited {
17791                    ids: excerpt_ids.clone(),
17792                })
17793            }
17794            multi_buffer::Event::ExcerptsExpanded { ids } => {
17795                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17796                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
17797            }
17798            multi_buffer::Event::Reparsed(buffer_id) => {
17799                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17800                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17801
17802                cx.emit(EditorEvent::Reparsed(*buffer_id));
17803            }
17804            multi_buffer::Event::DiffHunksToggled => {
17805                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17806            }
17807            multi_buffer::Event::LanguageChanged(buffer_id) => {
17808                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
17809                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17810                cx.emit(EditorEvent::Reparsed(*buffer_id));
17811                cx.notify();
17812            }
17813            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
17814            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
17815            multi_buffer::Event::FileHandleChanged
17816            | multi_buffer::Event::Reloaded
17817            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
17818            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
17819            multi_buffer::Event::DiagnosticsUpdated => {
17820                self.refresh_active_diagnostics(cx);
17821                self.refresh_inline_diagnostics(true, window, cx);
17822                self.scrollbar_marker_state.dirty = true;
17823                cx.notify();
17824            }
17825            _ => {}
17826        };
17827    }
17828
17829    fn on_display_map_changed(
17830        &mut self,
17831        _: Entity<DisplayMap>,
17832        _: &mut Window,
17833        cx: &mut Context<Self>,
17834    ) {
17835        cx.notify();
17836    }
17837
17838    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17839        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17840        self.update_edit_prediction_settings(cx);
17841        self.refresh_inline_completion(true, false, window, cx);
17842        self.refresh_inlay_hints(
17843            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
17844                self.selections.newest_anchor().head(),
17845                &self.buffer.read(cx).snapshot(cx),
17846                cx,
17847            )),
17848            cx,
17849        );
17850
17851        let old_cursor_shape = self.cursor_shape;
17852
17853        {
17854            let editor_settings = EditorSettings::get_global(cx);
17855            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
17856            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
17857            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
17858            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
17859        }
17860
17861        if old_cursor_shape != self.cursor_shape {
17862            cx.emit(EditorEvent::CursorShapeChanged);
17863        }
17864
17865        let project_settings = ProjectSettings::get_global(cx);
17866        self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
17867
17868        if self.mode.is_full() {
17869            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
17870            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
17871            if self.show_inline_diagnostics != show_inline_diagnostics {
17872                self.show_inline_diagnostics = show_inline_diagnostics;
17873                self.refresh_inline_diagnostics(false, window, cx);
17874            }
17875
17876            if self.git_blame_inline_enabled != inline_blame_enabled {
17877                self.toggle_git_blame_inline_internal(false, window, cx);
17878            }
17879        }
17880
17881        cx.notify();
17882    }
17883
17884    pub fn set_searchable(&mut self, searchable: bool) {
17885        self.searchable = searchable;
17886    }
17887
17888    pub fn searchable(&self) -> bool {
17889        self.searchable
17890    }
17891
17892    fn open_proposed_changes_editor(
17893        &mut self,
17894        _: &OpenProposedChangesEditor,
17895        window: &mut Window,
17896        cx: &mut Context<Self>,
17897    ) {
17898        let Some(workspace) = self.workspace() else {
17899            cx.propagate();
17900            return;
17901        };
17902
17903        let selections = self.selections.all::<usize>(cx);
17904        let multi_buffer = self.buffer.read(cx);
17905        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17906        let mut new_selections_by_buffer = HashMap::default();
17907        for selection in selections {
17908            for (buffer, range, _) in
17909                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
17910            {
17911                let mut range = range.to_point(buffer);
17912                range.start.column = 0;
17913                range.end.column = buffer.line_len(range.end.row);
17914                new_selections_by_buffer
17915                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
17916                    .or_insert(Vec::new())
17917                    .push(range)
17918            }
17919        }
17920
17921        let proposed_changes_buffers = new_selections_by_buffer
17922            .into_iter()
17923            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
17924            .collect::<Vec<_>>();
17925        let proposed_changes_editor = cx.new(|cx| {
17926            ProposedChangesEditor::new(
17927                "Proposed changes",
17928                proposed_changes_buffers,
17929                self.project.clone(),
17930                window,
17931                cx,
17932            )
17933        });
17934
17935        window.defer(cx, move |window, cx| {
17936            workspace.update(cx, |workspace, cx| {
17937                workspace.active_pane().update(cx, |pane, cx| {
17938                    pane.add_item(
17939                        Box::new(proposed_changes_editor),
17940                        true,
17941                        true,
17942                        None,
17943                        window,
17944                        cx,
17945                    );
17946                });
17947            });
17948        });
17949    }
17950
17951    pub fn open_excerpts_in_split(
17952        &mut self,
17953        _: &OpenExcerptsSplit,
17954        window: &mut Window,
17955        cx: &mut Context<Self>,
17956    ) {
17957        self.open_excerpts_common(None, true, window, cx)
17958    }
17959
17960    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
17961        self.open_excerpts_common(None, false, window, cx)
17962    }
17963
17964    fn open_excerpts_common(
17965        &mut self,
17966        jump_data: Option<JumpData>,
17967        split: bool,
17968        window: &mut Window,
17969        cx: &mut Context<Self>,
17970    ) {
17971        let Some(workspace) = self.workspace() else {
17972            cx.propagate();
17973            return;
17974        };
17975
17976        if self.buffer.read(cx).is_singleton() {
17977            cx.propagate();
17978            return;
17979        }
17980
17981        let mut new_selections_by_buffer = HashMap::default();
17982        match &jump_data {
17983            Some(JumpData::MultiBufferPoint {
17984                excerpt_id,
17985                position,
17986                anchor,
17987                line_offset_from_top,
17988            }) => {
17989                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17990                if let Some(buffer) = multi_buffer_snapshot
17991                    .buffer_id_for_excerpt(*excerpt_id)
17992                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
17993                {
17994                    let buffer_snapshot = buffer.read(cx).snapshot();
17995                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
17996                        language::ToPoint::to_point(anchor, &buffer_snapshot)
17997                    } else {
17998                        buffer_snapshot.clip_point(*position, Bias::Left)
17999                    };
18000                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18001                    new_selections_by_buffer.insert(
18002                        buffer,
18003                        (
18004                            vec![jump_to_offset..jump_to_offset],
18005                            Some(*line_offset_from_top),
18006                        ),
18007                    );
18008                }
18009            }
18010            Some(JumpData::MultiBufferRow {
18011                row,
18012                line_offset_from_top,
18013            }) => {
18014                let point = MultiBufferPoint::new(row.0, 0);
18015                if let Some((buffer, buffer_point, _)) =
18016                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18017                {
18018                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18019                    new_selections_by_buffer
18020                        .entry(buffer)
18021                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18022                        .0
18023                        .push(buffer_offset..buffer_offset)
18024                }
18025            }
18026            None => {
18027                let selections = self.selections.all::<usize>(cx);
18028                let multi_buffer = self.buffer.read(cx);
18029                for selection in selections {
18030                    for (snapshot, range, _, anchor) in multi_buffer
18031                        .snapshot(cx)
18032                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18033                    {
18034                        if let Some(anchor) = anchor {
18035                            // selection is in a deleted hunk
18036                            let Some(buffer_id) = anchor.buffer_id else {
18037                                continue;
18038                            };
18039                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18040                                continue;
18041                            };
18042                            let offset = text::ToOffset::to_offset(
18043                                &anchor.text_anchor,
18044                                &buffer_handle.read(cx).snapshot(),
18045                            );
18046                            let range = offset..offset;
18047                            new_selections_by_buffer
18048                                .entry(buffer_handle)
18049                                .or_insert((Vec::new(), None))
18050                                .0
18051                                .push(range)
18052                        } else {
18053                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18054                            else {
18055                                continue;
18056                            };
18057                            new_selections_by_buffer
18058                                .entry(buffer_handle)
18059                                .or_insert((Vec::new(), None))
18060                                .0
18061                                .push(range)
18062                        }
18063                    }
18064                }
18065            }
18066        }
18067
18068        new_selections_by_buffer
18069            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18070
18071        if new_selections_by_buffer.is_empty() {
18072            return;
18073        }
18074
18075        // We defer the pane interaction because we ourselves are a workspace item
18076        // and activating a new item causes the pane to call a method on us reentrantly,
18077        // which panics if we're on the stack.
18078        window.defer(cx, move |window, cx| {
18079            workspace.update(cx, |workspace, cx| {
18080                let pane = if split {
18081                    workspace.adjacent_pane(window, cx)
18082                } else {
18083                    workspace.active_pane().clone()
18084                };
18085
18086                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18087                    let editor = buffer
18088                        .read(cx)
18089                        .file()
18090                        .is_none()
18091                        .then(|| {
18092                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18093                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18094                            // Instead, we try to activate the existing editor in the pane first.
18095                            let (editor, pane_item_index) =
18096                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18097                                    let editor = item.downcast::<Editor>()?;
18098                                    let singleton_buffer =
18099                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18100                                    if singleton_buffer == buffer {
18101                                        Some((editor, i))
18102                                    } else {
18103                                        None
18104                                    }
18105                                })?;
18106                            pane.update(cx, |pane, cx| {
18107                                pane.activate_item(pane_item_index, true, true, window, cx)
18108                            });
18109                            Some(editor)
18110                        })
18111                        .flatten()
18112                        .unwrap_or_else(|| {
18113                            workspace.open_project_item::<Self>(
18114                                pane.clone(),
18115                                buffer,
18116                                true,
18117                                true,
18118                                window,
18119                                cx,
18120                            )
18121                        });
18122
18123                    editor.update(cx, |editor, cx| {
18124                        let autoscroll = match scroll_offset {
18125                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18126                            None => Autoscroll::newest(),
18127                        };
18128                        let nav_history = editor.nav_history.take();
18129                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18130                            s.select_ranges(ranges);
18131                        });
18132                        editor.nav_history = nav_history;
18133                    });
18134                }
18135            })
18136        });
18137    }
18138
18139    // For now, don't allow opening excerpts in buffers that aren't backed by
18140    // regular project files.
18141    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18142        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18143    }
18144
18145    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18146        let snapshot = self.buffer.read(cx).read(cx);
18147        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18148        Some(
18149            ranges
18150                .iter()
18151                .map(move |range| {
18152                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18153                })
18154                .collect(),
18155        )
18156    }
18157
18158    fn selection_replacement_ranges(
18159        &self,
18160        range: Range<OffsetUtf16>,
18161        cx: &mut App,
18162    ) -> Vec<Range<OffsetUtf16>> {
18163        let selections = self.selections.all::<OffsetUtf16>(cx);
18164        let newest_selection = selections
18165            .iter()
18166            .max_by_key(|selection| selection.id)
18167            .unwrap();
18168        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18169        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18170        let snapshot = self.buffer.read(cx).read(cx);
18171        selections
18172            .into_iter()
18173            .map(|mut selection| {
18174                selection.start.0 =
18175                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18176                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18177                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18178                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18179            })
18180            .collect()
18181    }
18182
18183    fn report_editor_event(
18184        &self,
18185        event_type: &'static str,
18186        file_extension: Option<String>,
18187        cx: &App,
18188    ) {
18189        if cfg!(any(test, feature = "test-support")) {
18190            return;
18191        }
18192
18193        let Some(project) = &self.project else { return };
18194
18195        // If None, we are in a file without an extension
18196        let file = self
18197            .buffer
18198            .read(cx)
18199            .as_singleton()
18200            .and_then(|b| b.read(cx).file());
18201        let file_extension = file_extension.or(file
18202            .as_ref()
18203            .and_then(|file| Path::new(file.file_name(cx)).extension())
18204            .and_then(|e| e.to_str())
18205            .map(|a| a.to_string()));
18206
18207        let vim_mode = vim_enabled(cx);
18208
18209        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18210        let copilot_enabled = edit_predictions_provider
18211            == language::language_settings::EditPredictionProvider::Copilot;
18212        let copilot_enabled_for_language = self
18213            .buffer
18214            .read(cx)
18215            .language_settings(cx)
18216            .show_edit_predictions;
18217
18218        let project = project.read(cx);
18219        telemetry::event!(
18220            event_type,
18221            file_extension,
18222            vim_mode,
18223            copilot_enabled,
18224            copilot_enabled_for_language,
18225            edit_predictions_provider,
18226            is_via_ssh = project.is_via_ssh(),
18227        );
18228    }
18229
18230    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18231    /// with each line being an array of {text, highlight} objects.
18232    fn copy_highlight_json(
18233        &mut self,
18234        _: &CopyHighlightJson,
18235        window: &mut Window,
18236        cx: &mut Context<Self>,
18237    ) {
18238        #[derive(Serialize)]
18239        struct Chunk<'a> {
18240            text: String,
18241            highlight: Option<&'a str>,
18242        }
18243
18244        let snapshot = self.buffer.read(cx).snapshot(cx);
18245        let range = self
18246            .selected_text_range(false, window, cx)
18247            .and_then(|selection| {
18248                if selection.range.is_empty() {
18249                    None
18250                } else {
18251                    Some(selection.range)
18252                }
18253            })
18254            .unwrap_or_else(|| 0..snapshot.len());
18255
18256        let chunks = snapshot.chunks(range, true);
18257        let mut lines = Vec::new();
18258        let mut line: VecDeque<Chunk> = VecDeque::new();
18259
18260        let Some(style) = self.style.as_ref() else {
18261            return;
18262        };
18263
18264        for chunk in chunks {
18265            let highlight = chunk
18266                .syntax_highlight_id
18267                .and_then(|id| id.name(&style.syntax));
18268            let mut chunk_lines = chunk.text.split('\n').peekable();
18269            while let Some(text) = chunk_lines.next() {
18270                let mut merged_with_last_token = false;
18271                if let Some(last_token) = line.back_mut() {
18272                    if last_token.highlight == highlight {
18273                        last_token.text.push_str(text);
18274                        merged_with_last_token = true;
18275                    }
18276                }
18277
18278                if !merged_with_last_token {
18279                    line.push_back(Chunk {
18280                        text: text.into(),
18281                        highlight,
18282                    });
18283                }
18284
18285                if chunk_lines.peek().is_some() {
18286                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18287                        line.pop_front();
18288                    }
18289                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18290                        line.pop_back();
18291                    }
18292
18293                    lines.push(mem::take(&mut line));
18294                }
18295            }
18296        }
18297
18298        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18299            return;
18300        };
18301        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18302    }
18303
18304    pub fn open_context_menu(
18305        &mut self,
18306        _: &OpenContextMenu,
18307        window: &mut Window,
18308        cx: &mut Context<Self>,
18309    ) {
18310        self.request_autoscroll(Autoscroll::newest(), cx);
18311        let position = self.selections.newest_display(cx).start;
18312        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18313    }
18314
18315    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18316        &self.inlay_hint_cache
18317    }
18318
18319    pub fn replay_insert_event(
18320        &mut self,
18321        text: &str,
18322        relative_utf16_range: Option<Range<isize>>,
18323        window: &mut Window,
18324        cx: &mut Context<Self>,
18325    ) {
18326        if !self.input_enabled {
18327            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18328            return;
18329        }
18330        if let Some(relative_utf16_range) = relative_utf16_range {
18331            let selections = self.selections.all::<OffsetUtf16>(cx);
18332            self.change_selections(None, window, cx, |s| {
18333                let new_ranges = selections.into_iter().map(|range| {
18334                    let start = OffsetUtf16(
18335                        range
18336                            .head()
18337                            .0
18338                            .saturating_add_signed(relative_utf16_range.start),
18339                    );
18340                    let end = OffsetUtf16(
18341                        range
18342                            .head()
18343                            .0
18344                            .saturating_add_signed(relative_utf16_range.end),
18345                    );
18346                    start..end
18347                });
18348                s.select_ranges(new_ranges);
18349            });
18350        }
18351
18352        self.handle_input(text, window, cx);
18353    }
18354
18355    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18356        let Some(provider) = self.semantics_provider.as_ref() else {
18357            return false;
18358        };
18359
18360        let mut supports = false;
18361        self.buffer().update(cx, |this, cx| {
18362            this.for_each_buffer(|buffer| {
18363                supports |= provider.supports_inlay_hints(buffer, cx);
18364            });
18365        });
18366
18367        supports
18368    }
18369
18370    pub fn is_focused(&self, window: &Window) -> bool {
18371        self.focus_handle.is_focused(window)
18372    }
18373
18374    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18375        cx.emit(EditorEvent::Focused);
18376
18377        if let Some(descendant) = self
18378            .last_focused_descendant
18379            .take()
18380            .and_then(|descendant| descendant.upgrade())
18381        {
18382            window.focus(&descendant);
18383        } else {
18384            if let Some(blame) = self.blame.as_ref() {
18385                blame.update(cx, GitBlame::focus)
18386            }
18387
18388            self.blink_manager.update(cx, BlinkManager::enable);
18389            self.show_cursor_names(window, cx);
18390            self.buffer.update(cx, |buffer, cx| {
18391                buffer.finalize_last_transaction(cx);
18392                if self.leader_peer_id.is_none() {
18393                    buffer.set_active_selections(
18394                        &self.selections.disjoint_anchors(),
18395                        self.selections.line_mode,
18396                        self.cursor_shape,
18397                        cx,
18398                    );
18399                }
18400            });
18401        }
18402    }
18403
18404    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18405        cx.emit(EditorEvent::FocusedIn)
18406    }
18407
18408    fn handle_focus_out(
18409        &mut self,
18410        event: FocusOutEvent,
18411        _window: &mut Window,
18412        cx: &mut Context<Self>,
18413    ) {
18414        if event.blurred != self.focus_handle {
18415            self.last_focused_descendant = Some(event.blurred);
18416        }
18417        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18418    }
18419
18420    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18421        self.blink_manager.update(cx, BlinkManager::disable);
18422        self.buffer
18423            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18424
18425        if let Some(blame) = self.blame.as_ref() {
18426            blame.update(cx, GitBlame::blur)
18427        }
18428        if !self.hover_state.focused(window, cx) {
18429            hide_hover(self, cx);
18430        }
18431        if !self
18432            .context_menu
18433            .borrow()
18434            .as_ref()
18435            .is_some_and(|context_menu| context_menu.focused(window, cx))
18436        {
18437            self.hide_context_menu(window, cx);
18438        }
18439        self.discard_inline_completion(false, cx);
18440        cx.emit(EditorEvent::Blurred);
18441        cx.notify();
18442    }
18443
18444    pub fn register_action<A: Action>(
18445        &mut self,
18446        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18447    ) -> Subscription {
18448        let id = self.next_editor_action_id.post_inc();
18449        let listener = Arc::new(listener);
18450        self.editor_actions.borrow_mut().insert(
18451            id,
18452            Box::new(move |window, _| {
18453                let listener = listener.clone();
18454                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18455                    let action = action.downcast_ref().unwrap();
18456                    if phase == DispatchPhase::Bubble {
18457                        listener(action, window, cx)
18458                    }
18459                })
18460            }),
18461        );
18462
18463        let editor_actions = self.editor_actions.clone();
18464        Subscription::new(move || {
18465            editor_actions.borrow_mut().remove(&id);
18466        })
18467    }
18468
18469    pub fn file_header_size(&self) -> u32 {
18470        FILE_HEADER_HEIGHT
18471    }
18472
18473    pub fn restore(
18474        &mut self,
18475        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
18476        window: &mut Window,
18477        cx: &mut Context<Self>,
18478    ) {
18479        let workspace = self.workspace();
18480        let project = self.project.as_ref();
18481        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
18482            let mut tasks = Vec::new();
18483            for (buffer_id, changes) in revert_changes {
18484                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
18485                    buffer.update(cx, |buffer, cx| {
18486                        buffer.edit(
18487                            changes
18488                                .into_iter()
18489                                .map(|(range, text)| (range, text.to_string())),
18490                            None,
18491                            cx,
18492                        );
18493                    });
18494
18495                    if let Some(project) =
18496                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
18497                    {
18498                        project.update(cx, |project, cx| {
18499                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
18500                        })
18501                    }
18502                }
18503            }
18504            tasks
18505        });
18506        cx.spawn_in(window, async move |_, cx| {
18507            for (buffer, task) in save_tasks {
18508                let result = task.await;
18509                if result.is_err() {
18510                    let Some(path) = buffer
18511                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
18512                        .ok()
18513                    else {
18514                        continue;
18515                    };
18516                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
18517                        let Some(task) = cx
18518                            .update_window_entity(&workspace, |workspace, window, cx| {
18519                                workspace
18520                                    .open_path_preview(path, None, false, false, false, window, cx)
18521                            })
18522                            .ok()
18523                        else {
18524                            continue;
18525                        };
18526                        task.await.log_err();
18527                    }
18528                }
18529            }
18530        })
18531        .detach();
18532        self.change_selections(None, window, cx, |selections| selections.refresh());
18533    }
18534
18535    pub fn to_pixel_point(
18536        &self,
18537        source: multi_buffer::Anchor,
18538        editor_snapshot: &EditorSnapshot,
18539        window: &mut Window,
18540    ) -> Option<gpui::Point<Pixels>> {
18541        let source_point = source.to_display_point(editor_snapshot);
18542        self.display_to_pixel_point(source_point, editor_snapshot, window)
18543    }
18544
18545    pub fn display_to_pixel_point(
18546        &self,
18547        source: DisplayPoint,
18548        editor_snapshot: &EditorSnapshot,
18549        window: &mut Window,
18550    ) -> Option<gpui::Point<Pixels>> {
18551        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
18552        let text_layout_details = self.text_layout_details(window);
18553        let scroll_top = text_layout_details
18554            .scroll_anchor
18555            .scroll_position(editor_snapshot)
18556            .y;
18557
18558        if source.row().as_f32() < scroll_top.floor() {
18559            return None;
18560        }
18561        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
18562        let source_y = line_height * (source.row().as_f32() - scroll_top);
18563        Some(gpui::Point::new(source_x, source_y))
18564    }
18565
18566    pub fn has_visible_completions_menu(&self) -> bool {
18567        !self.edit_prediction_preview_is_active()
18568            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
18569                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
18570            })
18571    }
18572
18573    pub fn register_addon<T: Addon>(&mut self, instance: T) {
18574        self.addons
18575            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
18576    }
18577
18578    pub fn unregister_addon<T: Addon>(&mut self) {
18579        self.addons.remove(&std::any::TypeId::of::<T>());
18580    }
18581
18582    pub fn addon<T: Addon>(&self) -> Option<&T> {
18583        let type_id = std::any::TypeId::of::<T>();
18584        self.addons
18585            .get(&type_id)
18586            .and_then(|item| item.to_any().downcast_ref::<T>())
18587    }
18588
18589    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
18590        let type_id = std::any::TypeId::of::<T>();
18591        self.addons
18592            .get_mut(&type_id)
18593            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
18594    }
18595
18596    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
18597        let text_layout_details = self.text_layout_details(window);
18598        let style = &text_layout_details.editor_style;
18599        let font_id = window.text_system().resolve_font(&style.text.font());
18600        let font_size = style.text.font_size.to_pixels(window.rem_size());
18601        let line_height = style.text.line_height_in_pixels(window.rem_size());
18602        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
18603
18604        gpui::Size::new(em_width, line_height)
18605    }
18606
18607    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
18608        self.load_diff_task.clone()
18609    }
18610
18611    fn read_metadata_from_db(
18612        &mut self,
18613        item_id: u64,
18614        workspace_id: WorkspaceId,
18615        window: &mut Window,
18616        cx: &mut Context<Editor>,
18617    ) {
18618        if self.is_singleton(cx)
18619            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
18620        {
18621            let buffer_snapshot = OnceCell::new();
18622
18623            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
18624                if !folds.is_empty() {
18625                    let snapshot =
18626                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18627                    self.fold_ranges(
18628                        folds
18629                            .into_iter()
18630                            .map(|(start, end)| {
18631                                snapshot.clip_offset(start, Bias::Left)
18632                                    ..snapshot.clip_offset(end, Bias::Right)
18633                            })
18634                            .collect(),
18635                        false,
18636                        window,
18637                        cx,
18638                    );
18639                }
18640            }
18641
18642            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
18643                if !selections.is_empty() {
18644                    let snapshot =
18645                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18646                    self.change_selections(None, window, cx, |s| {
18647                        s.select_ranges(selections.into_iter().map(|(start, end)| {
18648                            snapshot.clip_offset(start, Bias::Left)
18649                                ..snapshot.clip_offset(end, Bias::Right)
18650                        }));
18651                    });
18652                }
18653            };
18654        }
18655
18656        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
18657    }
18658}
18659
18660fn vim_enabled(cx: &App) -> bool {
18661    cx.global::<SettingsStore>()
18662        .raw_user_settings()
18663        .get("vim_mode")
18664        == Some(&serde_json::Value::Bool(true))
18665}
18666
18667// Consider user intent and default settings
18668fn choose_completion_range(
18669    completion: &Completion,
18670    intent: CompletionIntent,
18671    buffer: &Entity<Buffer>,
18672    cx: &mut Context<Editor>,
18673) -> Range<usize> {
18674    fn should_replace(
18675        completion: &Completion,
18676        insert_range: &Range<text::Anchor>,
18677        intent: CompletionIntent,
18678        completion_mode_setting: LspInsertMode,
18679        buffer: &Buffer,
18680    ) -> bool {
18681        // specific actions take precedence over settings
18682        match intent {
18683            CompletionIntent::CompleteWithInsert => return false,
18684            CompletionIntent::CompleteWithReplace => return true,
18685            CompletionIntent::Complete | CompletionIntent::Compose => {}
18686        }
18687
18688        match completion_mode_setting {
18689            LspInsertMode::Insert => false,
18690            LspInsertMode::Replace => true,
18691            LspInsertMode::ReplaceSubsequence => {
18692                let mut text_to_replace = buffer.chars_for_range(
18693                    buffer.anchor_before(completion.replace_range.start)
18694                        ..buffer.anchor_after(completion.replace_range.end),
18695                );
18696                let mut completion_text = completion.new_text.chars();
18697
18698                // is `text_to_replace` a subsequence of `completion_text`
18699                text_to_replace
18700                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
18701            }
18702            LspInsertMode::ReplaceSuffix => {
18703                let range_after_cursor = insert_range.end..completion.replace_range.end;
18704
18705                let text_after_cursor = buffer
18706                    .text_for_range(
18707                        buffer.anchor_before(range_after_cursor.start)
18708                            ..buffer.anchor_after(range_after_cursor.end),
18709                    )
18710                    .collect::<String>();
18711                completion.new_text.ends_with(&text_after_cursor)
18712            }
18713        }
18714    }
18715
18716    let buffer = buffer.read(cx);
18717
18718    if let CompletionSource::Lsp {
18719        insert_range: Some(insert_range),
18720        ..
18721    } = &completion.source
18722    {
18723        let completion_mode_setting =
18724            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
18725                .completions
18726                .lsp_insert_mode;
18727
18728        if !should_replace(
18729            completion,
18730            &insert_range,
18731            intent,
18732            completion_mode_setting,
18733            buffer,
18734        ) {
18735            return insert_range.to_offset(buffer);
18736        }
18737    }
18738
18739    completion.replace_range.to_offset(buffer)
18740}
18741
18742fn insert_extra_newline_brackets(
18743    buffer: &MultiBufferSnapshot,
18744    range: Range<usize>,
18745    language: &language::LanguageScope,
18746) -> bool {
18747    let leading_whitespace_len = buffer
18748        .reversed_chars_at(range.start)
18749        .take_while(|c| c.is_whitespace() && *c != '\n')
18750        .map(|c| c.len_utf8())
18751        .sum::<usize>();
18752    let trailing_whitespace_len = buffer
18753        .chars_at(range.end)
18754        .take_while(|c| c.is_whitespace() && *c != '\n')
18755        .map(|c| c.len_utf8())
18756        .sum::<usize>();
18757    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
18758
18759    language.brackets().any(|(pair, enabled)| {
18760        let pair_start = pair.start.trim_end();
18761        let pair_end = pair.end.trim_start();
18762
18763        enabled
18764            && pair.newline
18765            && buffer.contains_str_at(range.end, pair_end)
18766            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
18767    })
18768}
18769
18770fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
18771    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
18772        [(buffer, range, _)] => (*buffer, range.clone()),
18773        _ => return false,
18774    };
18775    let pair = {
18776        let mut result: Option<BracketMatch> = None;
18777
18778        for pair in buffer
18779            .all_bracket_ranges(range.clone())
18780            .filter(move |pair| {
18781                pair.open_range.start <= range.start && pair.close_range.end >= range.end
18782            })
18783        {
18784            let len = pair.close_range.end - pair.open_range.start;
18785
18786            if let Some(existing) = &result {
18787                let existing_len = existing.close_range.end - existing.open_range.start;
18788                if len > existing_len {
18789                    continue;
18790                }
18791            }
18792
18793            result = Some(pair);
18794        }
18795
18796        result
18797    };
18798    let Some(pair) = pair else {
18799        return false;
18800    };
18801    pair.newline_only
18802        && buffer
18803            .chars_for_range(pair.open_range.end..range.start)
18804            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
18805            .all(|c| c.is_whitespace() && c != '\n')
18806}
18807
18808fn get_uncommitted_diff_for_buffer(
18809    project: &Entity<Project>,
18810    buffers: impl IntoIterator<Item = Entity<Buffer>>,
18811    buffer: Entity<MultiBuffer>,
18812    cx: &mut App,
18813) -> Task<()> {
18814    let mut tasks = Vec::new();
18815    project.update(cx, |project, cx| {
18816        for buffer in buffers {
18817            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
18818                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
18819            }
18820        }
18821    });
18822    cx.spawn(async move |cx| {
18823        let diffs = future::join_all(tasks).await;
18824        buffer
18825            .update(cx, |buffer, cx| {
18826                for diff in diffs.into_iter().flatten() {
18827                    buffer.add_diff(diff, cx);
18828                }
18829            })
18830            .ok();
18831    })
18832}
18833
18834fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
18835    let tab_size = tab_size.get() as usize;
18836    let mut width = offset;
18837
18838    for ch in text.chars() {
18839        width += if ch == '\t' {
18840            tab_size - (width % tab_size)
18841        } else {
18842            1
18843        };
18844    }
18845
18846    width - offset
18847}
18848
18849#[cfg(test)]
18850mod tests {
18851    use super::*;
18852
18853    #[test]
18854    fn test_string_size_with_expanded_tabs() {
18855        let nz = |val| NonZeroU32::new(val).unwrap();
18856        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
18857        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
18858        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
18859        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
18860        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
18861        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
18862        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
18863        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
18864    }
18865}
18866
18867/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
18868struct WordBreakingTokenizer<'a> {
18869    input: &'a str,
18870}
18871
18872impl<'a> WordBreakingTokenizer<'a> {
18873    fn new(input: &'a str) -> Self {
18874        Self { input }
18875    }
18876}
18877
18878fn is_char_ideographic(ch: char) -> bool {
18879    use unicode_script::Script::*;
18880    use unicode_script::UnicodeScript;
18881    matches!(ch.script(), Han | Tangut | Yi)
18882}
18883
18884fn is_grapheme_ideographic(text: &str) -> bool {
18885    text.chars().any(is_char_ideographic)
18886}
18887
18888fn is_grapheme_whitespace(text: &str) -> bool {
18889    text.chars().any(|x| x.is_whitespace())
18890}
18891
18892fn should_stay_with_preceding_ideograph(text: &str) -> bool {
18893    text.chars().next().map_or(false, |ch| {
18894        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
18895    })
18896}
18897
18898#[derive(PartialEq, Eq, Debug, Clone, Copy)]
18899enum WordBreakToken<'a> {
18900    Word { token: &'a str, grapheme_len: usize },
18901    InlineWhitespace { token: &'a str, grapheme_len: usize },
18902    Newline,
18903}
18904
18905impl<'a> Iterator for WordBreakingTokenizer<'a> {
18906    /// Yields a span, the count of graphemes in the token, and whether it was
18907    /// whitespace. Note that it also breaks at word boundaries.
18908    type Item = WordBreakToken<'a>;
18909
18910    fn next(&mut self) -> Option<Self::Item> {
18911        use unicode_segmentation::UnicodeSegmentation;
18912        if self.input.is_empty() {
18913            return None;
18914        }
18915
18916        let mut iter = self.input.graphemes(true).peekable();
18917        let mut offset = 0;
18918        let mut grapheme_len = 0;
18919        if let Some(first_grapheme) = iter.next() {
18920            let is_newline = first_grapheme == "\n";
18921            let is_whitespace = is_grapheme_whitespace(first_grapheme);
18922            offset += first_grapheme.len();
18923            grapheme_len += 1;
18924            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
18925                if let Some(grapheme) = iter.peek().copied() {
18926                    if should_stay_with_preceding_ideograph(grapheme) {
18927                        offset += grapheme.len();
18928                        grapheme_len += 1;
18929                    }
18930                }
18931            } else {
18932                let mut words = self.input[offset..].split_word_bound_indices().peekable();
18933                let mut next_word_bound = words.peek().copied();
18934                if next_word_bound.map_or(false, |(i, _)| i == 0) {
18935                    next_word_bound = words.next();
18936                }
18937                while let Some(grapheme) = iter.peek().copied() {
18938                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
18939                        break;
18940                    };
18941                    if is_grapheme_whitespace(grapheme) != is_whitespace
18942                        || (grapheme == "\n") != is_newline
18943                    {
18944                        break;
18945                    };
18946                    offset += grapheme.len();
18947                    grapheme_len += 1;
18948                    iter.next();
18949                }
18950            }
18951            let token = &self.input[..offset];
18952            self.input = &self.input[offset..];
18953            if token == "\n" {
18954                Some(WordBreakToken::Newline)
18955            } else if is_whitespace {
18956                Some(WordBreakToken::InlineWhitespace {
18957                    token,
18958                    grapheme_len,
18959                })
18960            } else {
18961                Some(WordBreakToken::Word {
18962                    token,
18963                    grapheme_len,
18964                })
18965            }
18966        } else {
18967            None
18968        }
18969    }
18970}
18971
18972#[test]
18973fn test_word_breaking_tokenizer() {
18974    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
18975        ("", &[]),
18976        ("  ", &[whitespace("  ", 2)]),
18977        ("Ʒ", &[word("Ʒ", 1)]),
18978        ("Ǽ", &[word("Ǽ", 1)]),
18979        ("", &[word("", 1)]),
18980        ("⋑⋑", &[word("⋑⋑", 2)]),
18981        (
18982            "原理,进而",
18983            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
18984        ),
18985        (
18986            "hello world",
18987            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
18988        ),
18989        (
18990            "hello, world",
18991            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
18992        ),
18993        (
18994            "  hello world",
18995            &[
18996                whitespace("  ", 2),
18997                word("hello", 5),
18998                whitespace(" ", 1),
18999                word("world", 5),
19000            ],
19001        ),
19002        (
19003            "这是什么 \n 钢笔",
19004            &[
19005                word("", 1),
19006                word("", 1),
19007                word("", 1),
19008                word("", 1),
19009                whitespace(" ", 1),
19010                newline(),
19011                whitespace(" ", 1),
19012                word("", 1),
19013                word("", 1),
19014            ],
19015        ),
19016        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19017    ];
19018
19019    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19020        WordBreakToken::Word {
19021            token,
19022            grapheme_len,
19023        }
19024    }
19025
19026    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19027        WordBreakToken::InlineWhitespace {
19028            token,
19029            grapheme_len,
19030        }
19031    }
19032
19033    fn newline() -> WordBreakToken<'static> {
19034        WordBreakToken::Newline
19035    }
19036
19037    for (input, result) in tests {
19038        assert_eq!(
19039            WordBreakingTokenizer::new(input)
19040                .collect::<Vec<_>>()
19041                .as_slice(),
19042            *result,
19043        );
19044    }
19045}
19046
19047fn wrap_with_prefix(
19048    line_prefix: String,
19049    unwrapped_text: String,
19050    wrap_column: usize,
19051    tab_size: NonZeroU32,
19052    preserve_existing_whitespace: bool,
19053) -> String {
19054    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19055    let mut wrapped_text = String::new();
19056    let mut current_line = line_prefix.clone();
19057
19058    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19059    let mut current_line_len = line_prefix_len;
19060    let mut in_whitespace = false;
19061    for token in tokenizer {
19062        let have_preceding_whitespace = in_whitespace;
19063        match token {
19064            WordBreakToken::Word {
19065                token,
19066                grapheme_len,
19067            } => {
19068                in_whitespace = false;
19069                if current_line_len + grapheme_len > wrap_column
19070                    && current_line_len != line_prefix_len
19071                {
19072                    wrapped_text.push_str(current_line.trim_end());
19073                    wrapped_text.push('\n');
19074                    current_line.truncate(line_prefix.len());
19075                    current_line_len = line_prefix_len;
19076                }
19077                current_line.push_str(token);
19078                current_line_len += grapheme_len;
19079            }
19080            WordBreakToken::InlineWhitespace {
19081                mut token,
19082                mut grapheme_len,
19083            } => {
19084                in_whitespace = true;
19085                if have_preceding_whitespace && !preserve_existing_whitespace {
19086                    continue;
19087                }
19088                if !preserve_existing_whitespace {
19089                    token = " ";
19090                    grapheme_len = 1;
19091                }
19092                if current_line_len + grapheme_len > wrap_column {
19093                    wrapped_text.push_str(current_line.trim_end());
19094                    wrapped_text.push('\n');
19095                    current_line.truncate(line_prefix.len());
19096                    current_line_len = line_prefix_len;
19097                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19098                    current_line.push_str(token);
19099                    current_line_len += grapheme_len;
19100                }
19101            }
19102            WordBreakToken::Newline => {
19103                in_whitespace = true;
19104                if preserve_existing_whitespace {
19105                    wrapped_text.push_str(current_line.trim_end());
19106                    wrapped_text.push('\n');
19107                    current_line.truncate(line_prefix.len());
19108                    current_line_len = line_prefix_len;
19109                } else if have_preceding_whitespace {
19110                    continue;
19111                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19112                {
19113                    wrapped_text.push_str(current_line.trim_end());
19114                    wrapped_text.push('\n');
19115                    current_line.truncate(line_prefix.len());
19116                    current_line_len = line_prefix_len;
19117                } else if current_line_len != line_prefix_len {
19118                    current_line.push(' ');
19119                    current_line_len += 1;
19120                }
19121            }
19122        }
19123    }
19124
19125    if !current_line.is_empty() {
19126        wrapped_text.push_str(&current_line);
19127    }
19128    wrapped_text
19129}
19130
19131#[test]
19132fn test_wrap_with_prefix() {
19133    assert_eq!(
19134        wrap_with_prefix(
19135            "# ".to_string(),
19136            "abcdefg".to_string(),
19137            4,
19138            NonZeroU32::new(4).unwrap(),
19139            false,
19140        ),
19141        "# abcdefg"
19142    );
19143    assert_eq!(
19144        wrap_with_prefix(
19145            "".to_string(),
19146            "\thello world".to_string(),
19147            8,
19148            NonZeroU32::new(4).unwrap(),
19149            false,
19150        ),
19151        "hello\nworld"
19152    );
19153    assert_eq!(
19154        wrap_with_prefix(
19155            "// ".to_string(),
19156            "xx \nyy zz aa bb cc".to_string(),
19157            12,
19158            NonZeroU32::new(4).unwrap(),
19159            false,
19160        ),
19161        "// xx yy zz\n// aa bb cc"
19162    );
19163    assert_eq!(
19164        wrap_with_prefix(
19165            String::new(),
19166            "这是什么 \n 钢笔".to_string(),
19167            3,
19168            NonZeroU32::new(4).unwrap(),
19169            false,
19170        ),
19171        "这是什\n么 钢\n"
19172    );
19173}
19174
19175pub trait CollaborationHub {
19176    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19177    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19178    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19179}
19180
19181impl CollaborationHub for Entity<Project> {
19182    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19183        self.read(cx).collaborators()
19184    }
19185
19186    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19187        self.read(cx).user_store().read(cx).participant_indices()
19188    }
19189
19190    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19191        let this = self.read(cx);
19192        let user_ids = this.collaborators().values().map(|c| c.user_id);
19193        this.user_store().read_with(cx, |user_store, cx| {
19194            user_store.participant_names(user_ids, cx)
19195        })
19196    }
19197}
19198
19199pub trait SemanticsProvider {
19200    fn hover(
19201        &self,
19202        buffer: &Entity<Buffer>,
19203        position: text::Anchor,
19204        cx: &mut App,
19205    ) -> Option<Task<Vec<project::Hover>>>;
19206
19207    fn inline_values(
19208        &self,
19209        buffer_handle: Entity<Buffer>,
19210        range: Range<text::Anchor>,
19211        cx: &mut App,
19212    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19213
19214    fn inlay_hints(
19215        &self,
19216        buffer_handle: Entity<Buffer>,
19217        range: Range<text::Anchor>,
19218        cx: &mut App,
19219    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19220
19221    fn resolve_inlay_hint(
19222        &self,
19223        hint: InlayHint,
19224        buffer_handle: Entity<Buffer>,
19225        server_id: LanguageServerId,
19226        cx: &mut App,
19227    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19228
19229    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19230
19231    fn document_highlights(
19232        &self,
19233        buffer: &Entity<Buffer>,
19234        position: text::Anchor,
19235        cx: &mut App,
19236    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19237
19238    fn definitions(
19239        &self,
19240        buffer: &Entity<Buffer>,
19241        position: text::Anchor,
19242        kind: GotoDefinitionKind,
19243        cx: &mut App,
19244    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19245
19246    fn range_for_rename(
19247        &self,
19248        buffer: &Entity<Buffer>,
19249        position: text::Anchor,
19250        cx: &mut App,
19251    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19252
19253    fn perform_rename(
19254        &self,
19255        buffer: &Entity<Buffer>,
19256        position: text::Anchor,
19257        new_name: String,
19258        cx: &mut App,
19259    ) -> Option<Task<Result<ProjectTransaction>>>;
19260}
19261
19262pub trait CompletionProvider {
19263    fn completions(
19264        &self,
19265        excerpt_id: ExcerptId,
19266        buffer: &Entity<Buffer>,
19267        buffer_position: text::Anchor,
19268        trigger: CompletionContext,
19269        window: &mut Window,
19270        cx: &mut Context<Editor>,
19271    ) -> Task<Result<Option<Vec<Completion>>>>;
19272
19273    fn resolve_completions(
19274        &self,
19275        buffer: Entity<Buffer>,
19276        completion_indices: Vec<usize>,
19277        completions: Rc<RefCell<Box<[Completion]>>>,
19278        cx: &mut Context<Editor>,
19279    ) -> Task<Result<bool>>;
19280
19281    fn apply_additional_edits_for_completion(
19282        &self,
19283        _buffer: Entity<Buffer>,
19284        _completions: Rc<RefCell<Box<[Completion]>>>,
19285        _completion_index: usize,
19286        _push_to_history: bool,
19287        _cx: &mut Context<Editor>,
19288    ) -> Task<Result<Option<language::Transaction>>> {
19289        Task::ready(Ok(None))
19290    }
19291
19292    fn is_completion_trigger(
19293        &self,
19294        buffer: &Entity<Buffer>,
19295        position: language::Anchor,
19296        text: &str,
19297        trigger_in_words: bool,
19298        cx: &mut Context<Editor>,
19299    ) -> bool;
19300
19301    fn sort_completions(&self) -> bool {
19302        true
19303    }
19304
19305    fn filter_completions(&self) -> bool {
19306        true
19307    }
19308}
19309
19310pub trait CodeActionProvider {
19311    fn id(&self) -> Arc<str>;
19312
19313    fn code_actions(
19314        &self,
19315        buffer: &Entity<Buffer>,
19316        range: Range<text::Anchor>,
19317        window: &mut Window,
19318        cx: &mut App,
19319    ) -> Task<Result<Vec<CodeAction>>>;
19320
19321    fn apply_code_action(
19322        &self,
19323        buffer_handle: Entity<Buffer>,
19324        action: CodeAction,
19325        excerpt_id: ExcerptId,
19326        push_to_history: bool,
19327        window: &mut Window,
19328        cx: &mut App,
19329    ) -> Task<Result<ProjectTransaction>>;
19330}
19331
19332impl CodeActionProvider for Entity<Project> {
19333    fn id(&self) -> Arc<str> {
19334        "project".into()
19335    }
19336
19337    fn code_actions(
19338        &self,
19339        buffer: &Entity<Buffer>,
19340        range: Range<text::Anchor>,
19341        _window: &mut Window,
19342        cx: &mut App,
19343    ) -> Task<Result<Vec<CodeAction>>> {
19344        self.update(cx, |project, cx| {
19345            let code_lens = project.code_lens(buffer, range.clone(), cx);
19346            let code_actions = project.code_actions(buffer, range, None, cx);
19347            cx.background_spawn(async move {
19348                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19349                Ok(code_lens
19350                    .context("code lens fetch")?
19351                    .into_iter()
19352                    .chain(code_actions.context("code action fetch")?)
19353                    .collect())
19354            })
19355        })
19356    }
19357
19358    fn apply_code_action(
19359        &self,
19360        buffer_handle: Entity<Buffer>,
19361        action: CodeAction,
19362        _excerpt_id: ExcerptId,
19363        push_to_history: bool,
19364        _window: &mut Window,
19365        cx: &mut App,
19366    ) -> Task<Result<ProjectTransaction>> {
19367        self.update(cx, |project, cx| {
19368            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19369        })
19370    }
19371}
19372
19373fn snippet_completions(
19374    project: &Project,
19375    buffer: &Entity<Buffer>,
19376    buffer_position: text::Anchor,
19377    cx: &mut App,
19378) -> Task<Result<Vec<Completion>>> {
19379    let languages = buffer.read(cx).languages_at(buffer_position);
19380    let snippet_store = project.snippets().read(cx);
19381
19382    let scopes: Vec<_> = languages
19383        .iter()
19384        .filter_map(|language| {
19385            let language_name = language.lsp_id();
19386            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19387
19388            if snippets.is_empty() {
19389                None
19390            } else {
19391                Some((language.default_scope(), snippets))
19392            }
19393        })
19394        .collect();
19395
19396    if scopes.is_empty() {
19397        return Task::ready(Ok(vec![]));
19398    }
19399
19400    let snapshot = buffer.read(cx).text_snapshot();
19401    let chars: String = snapshot
19402        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19403        .collect();
19404    let executor = cx.background_executor().clone();
19405
19406    cx.background_spawn(async move {
19407        let mut all_results: Vec<Completion> = Vec::new();
19408        for (scope, snippets) in scopes.into_iter() {
19409            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19410            let mut last_word = chars
19411                .chars()
19412                .take_while(|c| classifier.is_word(*c))
19413                .collect::<String>();
19414            last_word = last_word.chars().rev().collect();
19415
19416            if last_word.is_empty() {
19417                return Ok(vec![]);
19418            }
19419
19420            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19421            let to_lsp = |point: &text::Anchor| {
19422                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19423                point_to_lsp(end)
19424            };
19425            let lsp_end = to_lsp(&buffer_position);
19426
19427            let candidates = snippets
19428                .iter()
19429                .enumerate()
19430                .flat_map(|(ix, snippet)| {
19431                    snippet
19432                        .prefix
19433                        .iter()
19434                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19435                })
19436                .collect::<Vec<StringMatchCandidate>>();
19437
19438            let mut matches = fuzzy::match_strings(
19439                &candidates,
19440                &last_word,
19441                last_word.chars().any(|c| c.is_uppercase()),
19442                100,
19443                &Default::default(),
19444                executor.clone(),
19445            )
19446            .await;
19447
19448            // Remove all candidates where the query's start does not match the start of any word in the candidate
19449            if let Some(query_start) = last_word.chars().next() {
19450                matches.retain(|string_match| {
19451                    split_words(&string_match.string).any(|word| {
19452                        // Check that the first codepoint of the word as lowercase matches the first
19453                        // codepoint of the query as lowercase
19454                        word.chars()
19455                            .flat_map(|codepoint| codepoint.to_lowercase())
19456                            .zip(query_start.to_lowercase())
19457                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19458                    })
19459                });
19460            }
19461
19462            let matched_strings = matches
19463                .into_iter()
19464                .map(|m| m.string)
19465                .collect::<HashSet<_>>();
19466
19467            let mut result: Vec<Completion> = snippets
19468                .iter()
19469                .filter_map(|snippet| {
19470                    let matching_prefix = snippet
19471                        .prefix
19472                        .iter()
19473                        .find(|prefix| matched_strings.contains(*prefix))?;
19474                    let start = as_offset - last_word.len();
19475                    let start = snapshot.anchor_before(start);
19476                    let range = start..buffer_position;
19477                    let lsp_start = to_lsp(&start);
19478                    let lsp_range = lsp::Range {
19479                        start: lsp_start,
19480                        end: lsp_end,
19481                    };
19482                    Some(Completion {
19483                        replace_range: range,
19484                        new_text: snippet.body.clone(),
19485                        source: CompletionSource::Lsp {
19486                            insert_range: None,
19487                            server_id: LanguageServerId(usize::MAX),
19488                            resolved: true,
19489                            lsp_completion: Box::new(lsp::CompletionItem {
19490                                label: snippet.prefix.first().unwrap().clone(),
19491                                kind: Some(CompletionItemKind::SNIPPET),
19492                                label_details: snippet.description.as_ref().map(|description| {
19493                                    lsp::CompletionItemLabelDetails {
19494                                        detail: Some(description.clone()),
19495                                        description: None,
19496                                    }
19497                                }),
19498                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19499                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19500                                    lsp::InsertReplaceEdit {
19501                                        new_text: snippet.body.clone(),
19502                                        insert: lsp_range,
19503                                        replace: lsp_range,
19504                                    },
19505                                )),
19506                                filter_text: Some(snippet.body.clone()),
19507                                sort_text: Some(char::MAX.to_string()),
19508                                ..lsp::CompletionItem::default()
19509                            }),
19510                            lsp_defaults: None,
19511                        },
19512                        label: CodeLabel {
19513                            text: matching_prefix.clone(),
19514                            runs: Vec::new(),
19515                            filter_range: 0..matching_prefix.len(),
19516                        },
19517                        icon_path: None,
19518                        documentation: snippet.description.clone().map(|description| {
19519                            CompletionDocumentation::SingleLine(description.into())
19520                        }),
19521                        insert_text_mode: None,
19522                        confirm: None,
19523                    })
19524                })
19525                .collect();
19526
19527            all_results.append(&mut result);
19528        }
19529
19530        Ok(all_results)
19531    })
19532}
19533
19534impl CompletionProvider for Entity<Project> {
19535    fn completions(
19536        &self,
19537        _excerpt_id: ExcerptId,
19538        buffer: &Entity<Buffer>,
19539        buffer_position: text::Anchor,
19540        options: CompletionContext,
19541        _window: &mut Window,
19542        cx: &mut Context<Editor>,
19543    ) -> Task<Result<Option<Vec<Completion>>>> {
19544        self.update(cx, |project, cx| {
19545            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19546            let project_completions = project.completions(buffer, buffer_position, options, cx);
19547            cx.background_spawn(async move {
19548                let snippets_completions = snippets.await?;
19549                match project_completions.await? {
19550                    Some(mut completions) => {
19551                        completions.extend(snippets_completions);
19552                        Ok(Some(completions))
19553                    }
19554                    None => {
19555                        if snippets_completions.is_empty() {
19556                            Ok(None)
19557                        } else {
19558                            Ok(Some(snippets_completions))
19559                        }
19560                    }
19561                }
19562            })
19563        })
19564    }
19565
19566    fn resolve_completions(
19567        &self,
19568        buffer: Entity<Buffer>,
19569        completion_indices: Vec<usize>,
19570        completions: Rc<RefCell<Box<[Completion]>>>,
19571        cx: &mut Context<Editor>,
19572    ) -> Task<Result<bool>> {
19573        self.update(cx, |project, cx| {
19574            project.lsp_store().update(cx, |lsp_store, cx| {
19575                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19576            })
19577        })
19578    }
19579
19580    fn apply_additional_edits_for_completion(
19581        &self,
19582        buffer: Entity<Buffer>,
19583        completions: Rc<RefCell<Box<[Completion]>>>,
19584        completion_index: usize,
19585        push_to_history: bool,
19586        cx: &mut Context<Editor>,
19587    ) -> Task<Result<Option<language::Transaction>>> {
19588        self.update(cx, |project, cx| {
19589            project.lsp_store().update(cx, |lsp_store, cx| {
19590                lsp_store.apply_additional_edits_for_completion(
19591                    buffer,
19592                    completions,
19593                    completion_index,
19594                    push_to_history,
19595                    cx,
19596                )
19597            })
19598        })
19599    }
19600
19601    fn is_completion_trigger(
19602        &self,
19603        buffer: &Entity<Buffer>,
19604        position: language::Anchor,
19605        text: &str,
19606        trigger_in_words: bool,
19607        cx: &mut Context<Editor>,
19608    ) -> bool {
19609        let mut chars = text.chars();
19610        let char = if let Some(char) = chars.next() {
19611            char
19612        } else {
19613            return false;
19614        };
19615        if chars.next().is_some() {
19616            return false;
19617        }
19618
19619        let buffer = buffer.read(cx);
19620        let snapshot = buffer.snapshot();
19621        if !snapshot.settings_at(position, cx).show_completions_on_input {
19622            return false;
19623        }
19624        let classifier = snapshot.char_classifier_at(position).for_completion(true);
19625        if trigger_in_words && classifier.is_word(char) {
19626            return true;
19627        }
19628
19629        buffer.completion_triggers().contains(text)
19630    }
19631}
19632
19633impl SemanticsProvider for Entity<Project> {
19634    fn hover(
19635        &self,
19636        buffer: &Entity<Buffer>,
19637        position: text::Anchor,
19638        cx: &mut App,
19639    ) -> Option<Task<Vec<project::Hover>>> {
19640        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
19641    }
19642
19643    fn document_highlights(
19644        &self,
19645        buffer: &Entity<Buffer>,
19646        position: text::Anchor,
19647        cx: &mut App,
19648    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
19649        Some(self.update(cx, |project, cx| {
19650            project.document_highlights(buffer, position, cx)
19651        }))
19652    }
19653
19654    fn definitions(
19655        &self,
19656        buffer: &Entity<Buffer>,
19657        position: text::Anchor,
19658        kind: GotoDefinitionKind,
19659        cx: &mut App,
19660    ) -> Option<Task<Result<Vec<LocationLink>>>> {
19661        Some(self.update(cx, |project, cx| match kind {
19662            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
19663            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
19664            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
19665            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
19666        }))
19667    }
19668
19669    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
19670        // TODO: make this work for remote projects
19671        self.update(cx, |project, cx| {
19672            if project
19673                .active_debug_session(cx)
19674                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
19675            {
19676                return true;
19677            }
19678
19679            buffer.update(cx, |buffer, cx| {
19680                project.any_language_server_supports_inlay_hints(buffer, cx)
19681            })
19682        })
19683    }
19684
19685    fn inline_values(
19686        &self,
19687        buffer_handle: Entity<Buffer>,
19688        range: Range<text::Anchor>,
19689        cx: &mut App,
19690    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19691        self.update(cx, |project, cx| {
19692            let (session, active_stack_frame) = project.active_debug_session(cx)?;
19693
19694            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
19695        })
19696    }
19697
19698    fn inlay_hints(
19699        &self,
19700        buffer_handle: Entity<Buffer>,
19701        range: Range<text::Anchor>,
19702        cx: &mut App,
19703    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19704        Some(self.update(cx, |project, cx| {
19705            project.inlay_hints(buffer_handle, range, cx)
19706        }))
19707    }
19708
19709    fn resolve_inlay_hint(
19710        &self,
19711        hint: InlayHint,
19712        buffer_handle: Entity<Buffer>,
19713        server_id: LanguageServerId,
19714        cx: &mut App,
19715    ) -> Option<Task<anyhow::Result<InlayHint>>> {
19716        Some(self.update(cx, |project, cx| {
19717            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
19718        }))
19719    }
19720
19721    fn range_for_rename(
19722        &self,
19723        buffer: &Entity<Buffer>,
19724        position: text::Anchor,
19725        cx: &mut App,
19726    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
19727        Some(self.update(cx, |project, cx| {
19728            let buffer = buffer.clone();
19729            let task = project.prepare_rename(buffer.clone(), position, cx);
19730            cx.spawn(async move |_, cx| {
19731                Ok(match task.await? {
19732                    PrepareRenameResponse::Success(range) => Some(range),
19733                    PrepareRenameResponse::InvalidPosition => None,
19734                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
19735                        // Fallback on using TreeSitter info to determine identifier range
19736                        buffer.update(cx, |buffer, _| {
19737                            let snapshot = buffer.snapshot();
19738                            let (range, kind) = snapshot.surrounding_word(position);
19739                            if kind != Some(CharKind::Word) {
19740                                return None;
19741                            }
19742                            Some(
19743                                snapshot.anchor_before(range.start)
19744                                    ..snapshot.anchor_after(range.end),
19745                            )
19746                        })?
19747                    }
19748                })
19749            })
19750        }))
19751    }
19752
19753    fn perform_rename(
19754        &self,
19755        buffer: &Entity<Buffer>,
19756        position: text::Anchor,
19757        new_name: String,
19758        cx: &mut App,
19759    ) -> Option<Task<Result<ProjectTransaction>>> {
19760        Some(self.update(cx, |project, cx| {
19761            project.perform_rename(buffer.clone(), position, new_name, cx)
19762        }))
19763    }
19764}
19765
19766fn inlay_hint_settings(
19767    location: Anchor,
19768    snapshot: &MultiBufferSnapshot,
19769    cx: &mut Context<Editor>,
19770) -> InlayHintSettings {
19771    let file = snapshot.file_at(location);
19772    let language = snapshot.language_at(location).map(|l| l.name());
19773    language_settings(language, file, cx).inlay_hints
19774}
19775
19776fn consume_contiguous_rows(
19777    contiguous_row_selections: &mut Vec<Selection<Point>>,
19778    selection: &Selection<Point>,
19779    display_map: &DisplaySnapshot,
19780    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
19781) -> (MultiBufferRow, MultiBufferRow) {
19782    contiguous_row_selections.push(selection.clone());
19783    let start_row = MultiBufferRow(selection.start.row);
19784    let mut end_row = ending_row(selection, display_map);
19785
19786    while let Some(next_selection) = selections.peek() {
19787        if next_selection.start.row <= end_row.0 {
19788            end_row = ending_row(next_selection, display_map);
19789            contiguous_row_selections.push(selections.next().unwrap().clone());
19790        } else {
19791            break;
19792        }
19793    }
19794    (start_row, end_row)
19795}
19796
19797fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
19798    if next_selection.end.column > 0 || next_selection.is_empty() {
19799        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
19800    } else {
19801        MultiBufferRow(next_selection.end.row)
19802    }
19803}
19804
19805impl EditorSnapshot {
19806    pub fn remote_selections_in_range<'a>(
19807        &'a self,
19808        range: &'a Range<Anchor>,
19809        collaboration_hub: &dyn CollaborationHub,
19810        cx: &'a App,
19811    ) -> impl 'a + Iterator<Item = RemoteSelection> {
19812        let participant_names = collaboration_hub.user_names(cx);
19813        let participant_indices = collaboration_hub.user_participant_indices(cx);
19814        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
19815        let collaborators_by_replica_id = collaborators_by_peer_id
19816            .iter()
19817            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
19818            .collect::<HashMap<_, _>>();
19819        self.buffer_snapshot
19820            .selections_in_range(range, false)
19821            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
19822                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
19823                let participant_index = participant_indices.get(&collaborator.user_id).copied();
19824                let user_name = participant_names.get(&collaborator.user_id).cloned();
19825                Some(RemoteSelection {
19826                    replica_id,
19827                    selection,
19828                    cursor_shape,
19829                    line_mode,
19830                    participant_index,
19831                    peer_id: collaborator.peer_id,
19832                    user_name,
19833                })
19834            })
19835    }
19836
19837    pub fn hunks_for_ranges(
19838        &self,
19839        ranges: impl IntoIterator<Item = Range<Point>>,
19840    ) -> Vec<MultiBufferDiffHunk> {
19841        let mut hunks = Vec::new();
19842        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
19843            HashMap::default();
19844        for query_range in ranges {
19845            let query_rows =
19846                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
19847            for hunk in self.buffer_snapshot.diff_hunks_in_range(
19848                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
19849            ) {
19850                // Include deleted hunks that are adjacent to the query range, because
19851                // otherwise they would be missed.
19852                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
19853                if hunk.status().is_deleted() {
19854                    intersects_range |= hunk.row_range.start == query_rows.end;
19855                    intersects_range |= hunk.row_range.end == query_rows.start;
19856                }
19857                if intersects_range {
19858                    if !processed_buffer_rows
19859                        .entry(hunk.buffer_id)
19860                        .or_default()
19861                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
19862                    {
19863                        continue;
19864                    }
19865                    hunks.push(hunk);
19866                }
19867            }
19868        }
19869
19870        hunks
19871    }
19872
19873    fn display_diff_hunks_for_rows<'a>(
19874        &'a self,
19875        display_rows: Range<DisplayRow>,
19876        folded_buffers: &'a HashSet<BufferId>,
19877    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
19878        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
19879        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
19880
19881        self.buffer_snapshot
19882            .diff_hunks_in_range(buffer_start..buffer_end)
19883            .filter_map(|hunk| {
19884                if folded_buffers.contains(&hunk.buffer_id) {
19885                    return None;
19886                }
19887
19888                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
19889                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
19890
19891                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
19892                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
19893
19894                let display_hunk = if hunk_display_start.column() != 0 {
19895                    DisplayDiffHunk::Folded {
19896                        display_row: hunk_display_start.row(),
19897                    }
19898                } else {
19899                    let mut end_row = hunk_display_end.row();
19900                    if hunk_display_end.column() > 0 {
19901                        end_row.0 += 1;
19902                    }
19903                    let is_created_file = hunk.is_created_file();
19904                    DisplayDiffHunk::Unfolded {
19905                        status: hunk.status(),
19906                        diff_base_byte_range: hunk.diff_base_byte_range,
19907                        display_row_range: hunk_display_start.row()..end_row,
19908                        multi_buffer_range: Anchor::range_in_buffer(
19909                            hunk.excerpt_id,
19910                            hunk.buffer_id,
19911                            hunk.buffer_range,
19912                        ),
19913                        is_created_file,
19914                    }
19915                };
19916
19917                Some(display_hunk)
19918            })
19919    }
19920
19921    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
19922        self.display_snapshot.buffer_snapshot.language_at(position)
19923    }
19924
19925    pub fn is_focused(&self) -> bool {
19926        self.is_focused
19927    }
19928
19929    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
19930        self.placeholder_text.as_ref()
19931    }
19932
19933    pub fn scroll_position(&self) -> gpui::Point<f32> {
19934        self.scroll_anchor.scroll_position(&self.display_snapshot)
19935    }
19936
19937    fn gutter_dimensions(
19938        &self,
19939        font_id: FontId,
19940        font_size: Pixels,
19941        max_line_number_width: Pixels,
19942        cx: &App,
19943    ) -> Option<GutterDimensions> {
19944        if !self.show_gutter {
19945            return None;
19946        }
19947
19948        let descent = cx.text_system().descent(font_id, font_size);
19949        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
19950        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
19951
19952        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
19953            matches!(
19954                ProjectSettings::get_global(cx).git.git_gutter,
19955                Some(GitGutterSetting::TrackedFiles)
19956            )
19957        });
19958        let gutter_settings = EditorSettings::get_global(cx).gutter;
19959        let show_line_numbers = self
19960            .show_line_numbers
19961            .unwrap_or(gutter_settings.line_numbers);
19962        let line_gutter_width = if show_line_numbers {
19963            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
19964            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
19965            max_line_number_width.max(min_width_for_number_on_gutter)
19966        } else {
19967            0.0.into()
19968        };
19969
19970        let show_code_actions = self
19971            .show_code_actions
19972            .unwrap_or(gutter_settings.code_actions);
19973
19974        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
19975        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
19976
19977        let git_blame_entries_width =
19978            self.git_blame_gutter_max_author_length
19979                .map(|max_author_length| {
19980                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19981                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
19982
19983                    /// The number of characters to dedicate to gaps and margins.
19984                    const SPACING_WIDTH: usize = 4;
19985
19986                    let max_char_count = max_author_length.min(renderer.max_author_length())
19987                        + ::git::SHORT_SHA_LENGTH
19988                        + MAX_RELATIVE_TIMESTAMP.len()
19989                        + SPACING_WIDTH;
19990
19991                    em_advance * max_char_count
19992                });
19993
19994        let is_singleton = self.buffer_snapshot.is_singleton();
19995
19996        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
19997        left_padding += if !is_singleton {
19998            em_width * 4.0
19999        } else if show_code_actions || show_runnables || show_breakpoints {
20000            em_width * 3.0
20001        } else if show_git_gutter && show_line_numbers {
20002            em_width * 2.0
20003        } else if show_git_gutter || show_line_numbers {
20004            em_width
20005        } else {
20006            px(0.)
20007        };
20008
20009        let shows_folds = is_singleton && gutter_settings.folds;
20010
20011        let right_padding = if shows_folds && show_line_numbers {
20012            em_width * 4.0
20013        } else if shows_folds || (!is_singleton && show_line_numbers) {
20014            em_width * 3.0
20015        } else if show_line_numbers {
20016            em_width
20017        } else {
20018            px(0.)
20019        };
20020
20021        Some(GutterDimensions {
20022            left_padding,
20023            right_padding,
20024            width: line_gutter_width + left_padding + right_padding,
20025            margin: -descent,
20026            git_blame_entries_width,
20027        })
20028    }
20029
20030    pub fn render_crease_toggle(
20031        &self,
20032        buffer_row: MultiBufferRow,
20033        row_contains_cursor: bool,
20034        editor: Entity<Editor>,
20035        window: &mut Window,
20036        cx: &mut App,
20037    ) -> Option<AnyElement> {
20038        let folded = self.is_line_folded(buffer_row);
20039        let mut is_foldable = false;
20040
20041        if let Some(crease) = self
20042            .crease_snapshot
20043            .query_row(buffer_row, &self.buffer_snapshot)
20044        {
20045            is_foldable = true;
20046            match crease {
20047                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20048                    if let Some(render_toggle) = render_toggle {
20049                        let toggle_callback =
20050                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20051                                if folded {
20052                                    editor.update(cx, |editor, cx| {
20053                                        editor.fold_at(buffer_row, window, cx)
20054                                    });
20055                                } else {
20056                                    editor.update(cx, |editor, cx| {
20057                                        editor.unfold_at(buffer_row, window, cx)
20058                                    });
20059                                }
20060                            });
20061                        return Some((render_toggle)(
20062                            buffer_row,
20063                            folded,
20064                            toggle_callback,
20065                            window,
20066                            cx,
20067                        ));
20068                    }
20069                }
20070            }
20071        }
20072
20073        is_foldable |= self.starts_indent(buffer_row);
20074
20075        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20076            Some(
20077                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20078                    .toggle_state(folded)
20079                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20080                        if folded {
20081                            this.unfold_at(buffer_row, window, cx);
20082                        } else {
20083                            this.fold_at(buffer_row, window, cx);
20084                        }
20085                    }))
20086                    .into_any_element(),
20087            )
20088        } else {
20089            None
20090        }
20091    }
20092
20093    pub fn render_crease_trailer(
20094        &self,
20095        buffer_row: MultiBufferRow,
20096        window: &mut Window,
20097        cx: &mut App,
20098    ) -> Option<AnyElement> {
20099        let folded = self.is_line_folded(buffer_row);
20100        if let Crease::Inline { render_trailer, .. } = self
20101            .crease_snapshot
20102            .query_row(buffer_row, &self.buffer_snapshot)?
20103        {
20104            let render_trailer = render_trailer.as_ref()?;
20105            Some(render_trailer(buffer_row, folded, window, cx))
20106        } else {
20107            None
20108        }
20109    }
20110}
20111
20112impl Deref for EditorSnapshot {
20113    type Target = DisplaySnapshot;
20114
20115    fn deref(&self) -> &Self::Target {
20116        &self.display_snapshot
20117    }
20118}
20119
20120#[derive(Clone, Debug, PartialEq, Eq)]
20121pub enum EditorEvent {
20122    InputIgnored {
20123        text: Arc<str>,
20124    },
20125    InputHandled {
20126        utf16_range_to_replace: Option<Range<isize>>,
20127        text: Arc<str>,
20128    },
20129    ExcerptsAdded {
20130        buffer: Entity<Buffer>,
20131        predecessor: ExcerptId,
20132        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20133    },
20134    ExcerptsRemoved {
20135        ids: Vec<ExcerptId>,
20136        removed_buffer_ids: Vec<BufferId>,
20137    },
20138    BufferFoldToggled {
20139        ids: Vec<ExcerptId>,
20140        folded: bool,
20141    },
20142    ExcerptsEdited {
20143        ids: Vec<ExcerptId>,
20144    },
20145    ExcerptsExpanded {
20146        ids: Vec<ExcerptId>,
20147    },
20148    BufferEdited,
20149    Edited {
20150        transaction_id: clock::Lamport,
20151    },
20152    Reparsed(BufferId),
20153    Focused,
20154    FocusedIn,
20155    Blurred,
20156    DirtyChanged,
20157    Saved,
20158    TitleChanged,
20159    DiffBaseChanged,
20160    SelectionsChanged {
20161        local: bool,
20162    },
20163    ScrollPositionChanged {
20164        local: bool,
20165        autoscroll: bool,
20166    },
20167    Closed,
20168    TransactionUndone {
20169        transaction_id: clock::Lamport,
20170    },
20171    TransactionBegun {
20172        transaction_id: clock::Lamport,
20173    },
20174    Reloaded,
20175    CursorShapeChanged,
20176    PushedToNavHistory {
20177        anchor: Anchor,
20178        is_deactivate: bool,
20179    },
20180}
20181
20182impl EventEmitter<EditorEvent> for Editor {}
20183
20184impl Focusable for Editor {
20185    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20186        self.focus_handle.clone()
20187    }
20188}
20189
20190impl Render for Editor {
20191    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20192        let settings = ThemeSettings::get_global(cx);
20193
20194        let mut text_style = match self.mode {
20195            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20196                color: cx.theme().colors().editor_foreground,
20197                font_family: settings.ui_font.family.clone(),
20198                font_features: settings.ui_font.features.clone(),
20199                font_fallbacks: settings.ui_font.fallbacks.clone(),
20200                font_size: rems(0.875).into(),
20201                font_weight: settings.ui_font.weight,
20202                line_height: relative(settings.buffer_line_height.value()),
20203                ..Default::default()
20204            },
20205            EditorMode::Full { .. } => TextStyle {
20206                color: cx.theme().colors().editor_foreground,
20207                font_family: settings.buffer_font.family.clone(),
20208                font_features: settings.buffer_font.features.clone(),
20209                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20210                font_size: settings.buffer_font_size(cx).into(),
20211                font_weight: settings.buffer_font.weight,
20212                line_height: relative(settings.buffer_line_height.value()),
20213                ..Default::default()
20214            },
20215        };
20216        if let Some(text_style_refinement) = &self.text_style_refinement {
20217            text_style.refine(text_style_refinement)
20218        }
20219
20220        let background = match self.mode {
20221            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20222            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20223            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20224        };
20225
20226        EditorElement::new(
20227            &cx.entity(),
20228            EditorStyle {
20229                background,
20230                local_player: cx.theme().players().local(),
20231                text: text_style,
20232                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20233                syntax: cx.theme().syntax().clone(),
20234                status: cx.theme().status().clone(),
20235                inlay_hints_style: make_inlay_hints_style(cx),
20236                inline_completion_styles: make_suggestion_styles(cx),
20237                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20238            },
20239        )
20240    }
20241}
20242
20243impl EntityInputHandler for Editor {
20244    fn text_for_range(
20245        &mut self,
20246        range_utf16: Range<usize>,
20247        adjusted_range: &mut Option<Range<usize>>,
20248        _: &mut Window,
20249        cx: &mut Context<Self>,
20250    ) -> Option<String> {
20251        let snapshot = self.buffer.read(cx).read(cx);
20252        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20253        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20254        if (start.0..end.0) != range_utf16 {
20255            adjusted_range.replace(start.0..end.0);
20256        }
20257        Some(snapshot.text_for_range(start..end).collect())
20258    }
20259
20260    fn selected_text_range(
20261        &mut self,
20262        ignore_disabled_input: bool,
20263        _: &mut Window,
20264        cx: &mut Context<Self>,
20265    ) -> Option<UTF16Selection> {
20266        // Prevent the IME menu from appearing when holding down an alphabetic key
20267        // while input is disabled.
20268        if !ignore_disabled_input && !self.input_enabled {
20269            return None;
20270        }
20271
20272        let selection = self.selections.newest::<OffsetUtf16>(cx);
20273        let range = selection.range();
20274
20275        Some(UTF16Selection {
20276            range: range.start.0..range.end.0,
20277            reversed: selection.reversed,
20278        })
20279    }
20280
20281    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20282        let snapshot = self.buffer.read(cx).read(cx);
20283        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20284        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20285    }
20286
20287    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20288        self.clear_highlights::<InputComposition>(cx);
20289        self.ime_transaction.take();
20290    }
20291
20292    fn replace_text_in_range(
20293        &mut self,
20294        range_utf16: Option<Range<usize>>,
20295        text: &str,
20296        window: &mut Window,
20297        cx: &mut Context<Self>,
20298    ) {
20299        if !self.input_enabled {
20300            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20301            return;
20302        }
20303
20304        self.transact(window, cx, |this, window, cx| {
20305            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20306                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20307                Some(this.selection_replacement_ranges(range_utf16, cx))
20308            } else {
20309                this.marked_text_ranges(cx)
20310            };
20311
20312            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20313                let newest_selection_id = this.selections.newest_anchor().id;
20314                this.selections
20315                    .all::<OffsetUtf16>(cx)
20316                    .iter()
20317                    .zip(ranges_to_replace.iter())
20318                    .find_map(|(selection, range)| {
20319                        if selection.id == newest_selection_id {
20320                            Some(
20321                                (range.start.0 as isize - selection.head().0 as isize)
20322                                    ..(range.end.0 as isize - selection.head().0 as isize),
20323                            )
20324                        } else {
20325                            None
20326                        }
20327                    })
20328            });
20329
20330            cx.emit(EditorEvent::InputHandled {
20331                utf16_range_to_replace: range_to_replace,
20332                text: text.into(),
20333            });
20334
20335            if let Some(new_selected_ranges) = new_selected_ranges {
20336                this.change_selections(None, window, cx, |selections| {
20337                    selections.select_ranges(new_selected_ranges)
20338                });
20339                this.backspace(&Default::default(), window, cx);
20340            }
20341
20342            this.handle_input(text, window, cx);
20343        });
20344
20345        if let Some(transaction) = self.ime_transaction {
20346            self.buffer.update(cx, |buffer, cx| {
20347                buffer.group_until_transaction(transaction, cx);
20348            });
20349        }
20350
20351        self.unmark_text(window, cx);
20352    }
20353
20354    fn replace_and_mark_text_in_range(
20355        &mut self,
20356        range_utf16: Option<Range<usize>>,
20357        text: &str,
20358        new_selected_range_utf16: Option<Range<usize>>,
20359        window: &mut Window,
20360        cx: &mut Context<Self>,
20361    ) {
20362        if !self.input_enabled {
20363            return;
20364        }
20365
20366        let transaction = self.transact(window, cx, |this, window, cx| {
20367            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20368                let snapshot = this.buffer.read(cx).read(cx);
20369                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20370                    for marked_range in &mut marked_ranges {
20371                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20372                        marked_range.start.0 += relative_range_utf16.start;
20373                        marked_range.start =
20374                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20375                        marked_range.end =
20376                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20377                    }
20378                }
20379                Some(marked_ranges)
20380            } else if let Some(range_utf16) = range_utf16 {
20381                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20382                Some(this.selection_replacement_ranges(range_utf16, cx))
20383            } else {
20384                None
20385            };
20386
20387            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20388                let newest_selection_id = this.selections.newest_anchor().id;
20389                this.selections
20390                    .all::<OffsetUtf16>(cx)
20391                    .iter()
20392                    .zip(ranges_to_replace.iter())
20393                    .find_map(|(selection, range)| {
20394                        if selection.id == newest_selection_id {
20395                            Some(
20396                                (range.start.0 as isize - selection.head().0 as isize)
20397                                    ..(range.end.0 as isize - selection.head().0 as isize),
20398                            )
20399                        } else {
20400                            None
20401                        }
20402                    })
20403            });
20404
20405            cx.emit(EditorEvent::InputHandled {
20406                utf16_range_to_replace: range_to_replace,
20407                text: text.into(),
20408            });
20409
20410            if let Some(ranges) = ranges_to_replace {
20411                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20412            }
20413
20414            let marked_ranges = {
20415                let snapshot = this.buffer.read(cx).read(cx);
20416                this.selections
20417                    .disjoint_anchors()
20418                    .iter()
20419                    .map(|selection| {
20420                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20421                    })
20422                    .collect::<Vec<_>>()
20423            };
20424
20425            if text.is_empty() {
20426                this.unmark_text(window, cx);
20427            } else {
20428                this.highlight_text::<InputComposition>(
20429                    marked_ranges.clone(),
20430                    HighlightStyle {
20431                        underline: Some(UnderlineStyle {
20432                            thickness: px(1.),
20433                            color: None,
20434                            wavy: false,
20435                        }),
20436                        ..Default::default()
20437                    },
20438                    cx,
20439                );
20440            }
20441
20442            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20443            let use_autoclose = this.use_autoclose;
20444            let use_auto_surround = this.use_auto_surround;
20445            this.set_use_autoclose(false);
20446            this.set_use_auto_surround(false);
20447            this.handle_input(text, window, cx);
20448            this.set_use_autoclose(use_autoclose);
20449            this.set_use_auto_surround(use_auto_surround);
20450
20451            if let Some(new_selected_range) = new_selected_range_utf16 {
20452                let snapshot = this.buffer.read(cx).read(cx);
20453                let new_selected_ranges = marked_ranges
20454                    .into_iter()
20455                    .map(|marked_range| {
20456                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20457                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20458                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20459                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20460                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20461                    })
20462                    .collect::<Vec<_>>();
20463
20464                drop(snapshot);
20465                this.change_selections(None, window, cx, |selections| {
20466                    selections.select_ranges(new_selected_ranges)
20467                });
20468            }
20469        });
20470
20471        self.ime_transaction = self.ime_transaction.or(transaction);
20472        if let Some(transaction) = self.ime_transaction {
20473            self.buffer.update(cx, |buffer, cx| {
20474                buffer.group_until_transaction(transaction, cx);
20475            });
20476        }
20477
20478        if self.text_highlights::<InputComposition>(cx).is_none() {
20479            self.ime_transaction.take();
20480        }
20481    }
20482
20483    fn bounds_for_range(
20484        &mut self,
20485        range_utf16: Range<usize>,
20486        element_bounds: gpui::Bounds<Pixels>,
20487        window: &mut Window,
20488        cx: &mut Context<Self>,
20489    ) -> Option<gpui::Bounds<Pixels>> {
20490        let text_layout_details = self.text_layout_details(window);
20491        let gpui::Size {
20492            width: em_width,
20493            height: line_height,
20494        } = self.character_size(window);
20495
20496        let snapshot = self.snapshot(window, cx);
20497        let scroll_position = snapshot.scroll_position();
20498        let scroll_left = scroll_position.x * em_width;
20499
20500        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20501        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20502            + self.gutter_dimensions.width
20503            + self.gutter_dimensions.margin;
20504        let y = line_height * (start.row().as_f32() - scroll_position.y);
20505
20506        Some(Bounds {
20507            origin: element_bounds.origin + point(x, y),
20508            size: size(em_width, line_height),
20509        })
20510    }
20511
20512    fn character_index_for_point(
20513        &mut self,
20514        point: gpui::Point<Pixels>,
20515        _window: &mut Window,
20516        _cx: &mut Context<Self>,
20517    ) -> Option<usize> {
20518        let position_map = self.last_position_map.as_ref()?;
20519        if !position_map.text_hitbox.contains(&point) {
20520            return None;
20521        }
20522        let display_point = position_map.point_for_position(point).previous_valid;
20523        let anchor = position_map
20524            .snapshot
20525            .display_point_to_anchor(display_point, Bias::Left);
20526        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20527        Some(utf16_offset.0)
20528    }
20529}
20530
20531trait SelectionExt {
20532    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20533    fn spanned_rows(
20534        &self,
20535        include_end_if_at_line_start: bool,
20536        map: &DisplaySnapshot,
20537    ) -> Range<MultiBufferRow>;
20538}
20539
20540impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20541    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20542        let start = self
20543            .start
20544            .to_point(&map.buffer_snapshot)
20545            .to_display_point(map);
20546        let end = self
20547            .end
20548            .to_point(&map.buffer_snapshot)
20549            .to_display_point(map);
20550        if self.reversed {
20551            end..start
20552        } else {
20553            start..end
20554        }
20555    }
20556
20557    fn spanned_rows(
20558        &self,
20559        include_end_if_at_line_start: bool,
20560        map: &DisplaySnapshot,
20561    ) -> Range<MultiBufferRow> {
20562        let start = self.start.to_point(&map.buffer_snapshot);
20563        let mut end = self.end.to_point(&map.buffer_snapshot);
20564        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20565            end.row -= 1;
20566        }
20567
20568        let buffer_start = map.prev_line_boundary(start).0;
20569        let buffer_end = map.next_line_boundary(end).0;
20570        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20571    }
20572}
20573
20574impl<T: InvalidationRegion> InvalidationStack<T> {
20575    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20576    where
20577        S: Clone + ToOffset,
20578    {
20579        while let Some(region) = self.last() {
20580            let all_selections_inside_invalidation_ranges =
20581                if selections.len() == region.ranges().len() {
20582                    selections
20583                        .iter()
20584                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20585                        .all(|(selection, invalidation_range)| {
20586                            let head = selection.head().to_offset(buffer);
20587                            invalidation_range.start <= head && invalidation_range.end >= head
20588                        })
20589                } else {
20590                    false
20591                };
20592
20593            if all_selections_inside_invalidation_ranges {
20594                break;
20595            } else {
20596                self.pop();
20597            }
20598        }
20599    }
20600}
20601
20602impl<T> Default for InvalidationStack<T> {
20603    fn default() -> Self {
20604        Self(Default::default())
20605    }
20606}
20607
20608impl<T> Deref for InvalidationStack<T> {
20609    type Target = Vec<T>;
20610
20611    fn deref(&self) -> &Self::Target {
20612        &self.0
20613    }
20614}
20615
20616impl<T> DerefMut for InvalidationStack<T> {
20617    fn deref_mut(&mut self) -> &mut Self::Target {
20618        &mut self.0
20619    }
20620}
20621
20622impl InvalidationRegion for SnippetState {
20623    fn ranges(&self) -> &[Range<Anchor>] {
20624        &self.ranges[self.active_index]
20625    }
20626}
20627
20628fn inline_completion_edit_text(
20629    current_snapshot: &BufferSnapshot,
20630    edits: &[(Range<Anchor>, String)],
20631    edit_preview: &EditPreview,
20632    include_deletions: bool,
20633    cx: &App,
20634) -> HighlightedText {
20635    let edits = edits
20636        .iter()
20637        .map(|(anchor, text)| {
20638            (
20639                anchor.start.text_anchor..anchor.end.text_anchor,
20640                text.clone(),
20641            )
20642        })
20643        .collect::<Vec<_>>();
20644
20645    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
20646}
20647
20648pub fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla {
20649    match severity {
20650        DiagnosticSeverity::ERROR => colors.error,
20651        DiagnosticSeverity::WARNING => colors.warning,
20652        DiagnosticSeverity::INFORMATION => colors.info,
20653        DiagnosticSeverity::HINT => colors.info,
20654        _ => colors.ignored,
20655    }
20656}
20657
20658pub fn styled_runs_for_code_label<'a>(
20659    label: &'a CodeLabel,
20660    syntax_theme: &'a theme::SyntaxTheme,
20661) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
20662    let fade_out = HighlightStyle {
20663        fade_out: Some(0.35),
20664        ..Default::default()
20665    };
20666
20667    let mut prev_end = label.filter_range.end;
20668    label
20669        .runs
20670        .iter()
20671        .enumerate()
20672        .flat_map(move |(ix, (range, highlight_id))| {
20673            let style = if let Some(style) = highlight_id.style(syntax_theme) {
20674                style
20675            } else {
20676                return Default::default();
20677            };
20678            let mut muted_style = style;
20679            muted_style.highlight(fade_out);
20680
20681            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
20682            if range.start >= label.filter_range.end {
20683                if range.start > prev_end {
20684                    runs.push((prev_end..range.start, fade_out));
20685                }
20686                runs.push((range.clone(), muted_style));
20687            } else if range.end <= label.filter_range.end {
20688                runs.push((range.clone(), style));
20689            } else {
20690                runs.push((range.start..label.filter_range.end, style));
20691                runs.push((label.filter_range.end..range.end, muted_style));
20692            }
20693            prev_end = cmp::max(prev_end, range.end);
20694
20695            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
20696                runs.push((prev_end..label.text.len(), fade_out));
20697            }
20698
20699            runs
20700        })
20701}
20702
20703pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
20704    let mut prev_index = 0;
20705    let mut prev_codepoint: Option<char> = None;
20706    text.char_indices()
20707        .chain([(text.len(), '\0')])
20708        .filter_map(move |(index, codepoint)| {
20709            let prev_codepoint = prev_codepoint.replace(codepoint)?;
20710            let is_boundary = index == text.len()
20711                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
20712                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
20713            if is_boundary {
20714                let chunk = &text[prev_index..index];
20715                prev_index = index;
20716                Some(chunk)
20717            } else {
20718                None
20719            }
20720        })
20721}
20722
20723pub trait RangeToAnchorExt: Sized {
20724    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
20725
20726    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
20727        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
20728        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
20729    }
20730}
20731
20732impl<T: ToOffset> RangeToAnchorExt for Range<T> {
20733    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
20734        let start_offset = self.start.to_offset(snapshot);
20735        let end_offset = self.end.to_offset(snapshot);
20736        if start_offset == end_offset {
20737            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
20738        } else {
20739            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
20740        }
20741    }
20742}
20743
20744pub trait RowExt {
20745    fn as_f32(&self) -> f32;
20746
20747    fn next_row(&self) -> Self;
20748
20749    fn previous_row(&self) -> Self;
20750
20751    fn minus(&self, other: Self) -> u32;
20752}
20753
20754impl RowExt for DisplayRow {
20755    fn as_f32(&self) -> f32 {
20756        self.0 as f32
20757    }
20758
20759    fn next_row(&self) -> Self {
20760        Self(self.0 + 1)
20761    }
20762
20763    fn previous_row(&self) -> Self {
20764        Self(self.0.saturating_sub(1))
20765    }
20766
20767    fn minus(&self, other: Self) -> u32 {
20768        self.0 - other.0
20769    }
20770}
20771
20772impl RowExt for MultiBufferRow {
20773    fn as_f32(&self) -> f32 {
20774        self.0 as f32
20775    }
20776
20777    fn next_row(&self) -> Self {
20778        Self(self.0 + 1)
20779    }
20780
20781    fn previous_row(&self) -> Self {
20782        Self(self.0.saturating_sub(1))
20783    }
20784
20785    fn minus(&self, other: Self) -> u32 {
20786        self.0 - other.0
20787    }
20788}
20789
20790trait RowRangeExt {
20791    type Row;
20792
20793    fn len(&self) -> usize;
20794
20795    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
20796}
20797
20798impl RowRangeExt for Range<MultiBufferRow> {
20799    type Row = MultiBufferRow;
20800
20801    fn len(&self) -> usize {
20802        (self.end.0 - self.start.0) as usize
20803    }
20804
20805    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
20806        (self.start.0..self.end.0).map(MultiBufferRow)
20807    }
20808}
20809
20810impl RowRangeExt for Range<DisplayRow> {
20811    type Row = DisplayRow;
20812
20813    fn len(&self) -> usize {
20814        (self.end.0 - self.start.0) as usize
20815    }
20816
20817    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
20818        (self.start.0..self.end.0).map(DisplayRow)
20819    }
20820}
20821
20822/// If select range has more than one line, we
20823/// just point the cursor to range.start.
20824fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
20825    if range.start.row == range.end.row {
20826        range
20827    } else {
20828        range.start..range.start
20829    }
20830}
20831pub struct KillRing(ClipboardItem);
20832impl Global for KillRing {}
20833
20834const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
20835
20836enum BreakpointPromptEditAction {
20837    Log,
20838    Condition,
20839    HitCondition,
20840}
20841
20842struct BreakpointPromptEditor {
20843    pub(crate) prompt: Entity<Editor>,
20844    editor: WeakEntity<Editor>,
20845    breakpoint_anchor: Anchor,
20846    breakpoint: Breakpoint,
20847    edit_action: BreakpointPromptEditAction,
20848    block_ids: HashSet<CustomBlockId>,
20849    gutter_dimensions: Arc<Mutex<GutterDimensions>>,
20850    _subscriptions: Vec<Subscription>,
20851}
20852
20853impl BreakpointPromptEditor {
20854    const MAX_LINES: u8 = 4;
20855
20856    fn new(
20857        editor: WeakEntity<Editor>,
20858        breakpoint_anchor: Anchor,
20859        breakpoint: Breakpoint,
20860        edit_action: BreakpointPromptEditAction,
20861        window: &mut Window,
20862        cx: &mut Context<Self>,
20863    ) -> Self {
20864        let base_text = match edit_action {
20865            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
20866            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
20867            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
20868        }
20869        .map(|msg| msg.to_string())
20870        .unwrap_or_default();
20871
20872        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
20873        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
20874
20875        let prompt = cx.new(|cx| {
20876            let mut prompt = Editor::new(
20877                EditorMode::AutoHeight {
20878                    max_lines: Self::MAX_LINES as usize,
20879                },
20880                buffer,
20881                None,
20882                window,
20883                cx,
20884            );
20885            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
20886            prompt.set_show_cursor_when_unfocused(false, cx);
20887            prompt.set_placeholder_text(
20888                match edit_action {
20889                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
20890                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
20891                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
20892                },
20893                cx,
20894            );
20895
20896            prompt
20897        });
20898
20899        Self {
20900            prompt,
20901            editor,
20902            breakpoint_anchor,
20903            breakpoint,
20904            edit_action,
20905            gutter_dimensions: Arc::new(Mutex::new(GutterDimensions::default())),
20906            block_ids: Default::default(),
20907            _subscriptions: vec![],
20908        }
20909    }
20910
20911    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
20912        self.block_ids.extend(block_ids)
20913    }
20914
20915    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
20916        if let Some(editor) = self.editor.upgrade() {
20917            let message = self
20918                .prompt
20919                .read(cx)
20920                .buffer
20921                .read(cx)
20922                .as_singleton()
20923                .expect("A multi buffer in breakpoint prompt isn't possible")
20924                .read(cx)
20925                .as_rope()
20926                .to_string();
20927
20928            editor.update(cx, |editor, cx| {
20929                editor.edit_breakpoint_at_anchor(
20930                    self.breakpoint_anchor,
20931                    self.breakpoint.clone(),
20932                    match self.edit_action {
20933                        BreakpointPromptEditAction::Log => {
20934                            BreakpointEditAction::EditLogMessage(message.into())
20935                        }
20936                        BreakpointPromptEditAction::Condition => {
20937                            BreakpointEditAction::EditCondition(message.into())
20938                        }
20939                        BreakpointPromptEditAction::HitCondition => {
20940                            BreakpointEditAction::EditHitCondition(message.into())
20941                        }
20942                    },
20943                    cx,
20944                );
20945
20946                editor.remove_blocks(self.block_ids.clone(), None, cx);
20947                cx.focus_self(window);
20948            });
20949        }
20950    }
20951
20952    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
20953        self.editor
20954            .update(cx, |editor, cx| {
20955                editor.remove_blocks(self.block_ids.clone(), None, cx);
20956                window.focus(&editor.focus_handle);
20957            })
20958            .log_err();
20959    }
20960
20961    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
20962        let settings = ThemeSettings::get_global(cx);
20963        let text_style = TextStyle {
20964            color: if self.prompt.read(cx).read_only(cx) {
20965                cx.theme().colors().text_disabled
20966            } else {
20967                cx.theme().colors().text
20968            },
20969            font_family: settings.buffer_font.family.clone(),
20970            font_fallbacks: settings.buffer_font.fallbacks.clone(),
20971            font_size: settings.buffer_font_size(cx).into(),
20972            font_weight: settings.buffer_font.weight,
20973            line_height: relative(settings.buffer_line_height.value()),
20974            ..Default::default()
20975        };
20976        EditorElement::new(
20977            &self.prompt,
20978            EditorStyle {
20979                background: cx.theme().colors().editor_background,
20980                local_player: cx.theme().players().local(),
20981                text: text_style,
20982                ..Default::default()
20983            },
20984        )
20985    }
20986}
20987
20988impl Render for BreakpointPromptEditor {
20989    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20990        let gutter_dimensions = *self.gutter_dimensions.lock();
20991        h_flex()
20992            .key_context("Editor")
20993            .bg(cx.theme().colors().editor_background)
20994            .border_y_1()
20995            .border_color(cx.theme().status().info_border)
20996            .size_full()
20997            .py(window.line_height() / 2.5)
20998            .on_action(cx.listener(Self::confirm))
20999            .on_action(cx.listener(Self::cancel))
21000            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21001            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21002    }
21003}
21004
21005impl Focusable for BreakpointPromptEditor {
21006    fn focus_handle(&self, cx: &App) -> FocusHandle {
21007        self.prompt.focus_handle(cx)
21008    }
21009}
21010
21011fn all_edits_insertions_or_deletions(
21012    edits: &Vec<(Range<Anchor>, String)>,
21013    snapshot: &MultiBufferSnapshot,
21014) -> bool {
21015    let mut all_insertions = true;
21016    let mut all_deletions = true;
21017
21018    for (range, new_text) in edits.iter() {
21019        let range_is_empty = range.to_offset(&snapshot).is_empty();
21020        let text_is_empty = new_text.is_empty();
21021
21022        if range_is_empty != text_is_empty {
21023            if range_is_empty {
21024                all_deletions = false;
21025            } else {
21026                all_insertions = false;
21027            }
21028        } else {
21029            return false;
21030        }
21031
21032        if !all_insertions && !all_deletions {
21033            return false;
21034        }
21035    }
21036    all_insertions || all_deletions
21037}
21038
21039struct MissingEditPredictionKeybindingTooltip;
21040
21041impl Render for MissingEditPredictionKeybindingTooltip {
21042    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21043        ui::tooltip_container(window, cx, |container, _, cx| {
21044            container
21045                .flex_shrink_0()
21046                .max_w_80()
21047                .min_h(rems_from_px(124.))
21048                .justify_between()
21049                .child(
21050                    v_flex()
21051                        .flex_1()
21052                        .text_ui_sm(cx)
21053                        .child(Label::new("Conflict with Accept Keybinding"))
21054                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21055                )
21056                .child(
21057                    h_flex()
21058                        .pb_1()
21059                        .gap_1()
21060                        .items_end()
21061                        .w_full()
21062                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21063                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21064                        }))
21065                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21066                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21067                        })),
21068                )
21069        })
21070    }
21071}
21072
21073#[derive(Debug, Clone, Copy, PartialEq)]
21074pub struct LineHighlight {
21075    pub background: Background,
21076    pub border: Option<gpui::Hsla>,
21077    pub include_gutter: bool,
21078    pub type_id: Option<TypeId>,
21079}
21080
21081fn render_diff_hunk_controls(
21082    row: u32,
21083    status: &DiffHunkStatus,
21084    hunk_range: Range<Anchor>,
21085    is_created_file: bool,
21086    line_height: Pixels,
21087    editor: &Entity<Editor>,
21088    _window: &mut Window,
21089    cx: &mut App,
21090) -> AnyElement {
21091    h_flex()
21092        .h(line_height)
21093        .mr_1()
21094        .gap_1()
21095        .px_0p5()
21096        .pb_1()
21097        .border_x_1()
21098        .border_b_1()
21099        .border_color(cx.theme().colors().border_variant)
21100        .rounded_b_lg()
21101        .bg(cx.theme().colors().editor_background)
21102        .gap_1()
21103        .occlude()
21104        .shadow_md()
21105        .child(if status.has_secondary_hunk() {
21106            Button::new(("stage", row as u64), "Stage")
21107                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21108                .tooltip({
21109                    let focus_handle = editor.focus_handle(cx);
21110                    move |window, cx| {
21111                        Tooltip::for_action_in(
21112                            "Stage Hunk",
21113                            &::git::ToggleStaged,
21114                            &focus_handle,
21115                            window,
21116                            cx,
21117                        )
21118                    }
21119                })
21120                .on_click({
21121                    let editor = editor.clone();
21122                    move |_event, _window, cx| {
21123                        editor.update(cx, |editor, cx| {
21124                            editor.stage_or_unstage_diff_hunks(
21125                                true,
21126                                vec![hunk_range.start..hunk_range.start],
21127                                cx,
21128                            );
21129                        });
21130                    }
21131                })
21132        } else {
21133            Button::new(("unstage", row as u64), "Unstage")
21134                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21135                .tooltip({
21136                    let focus_handle = editor.focus_handle(cx);
21137                    move |window, cx| {
21138                        Tooltip::for_action_in(
21139                            "Unstage Hunk",
21140                            &::git::ToggleStaged,
21141                            &focus_handle,
21142                            window,
21143                            cx,
21144                        )
21145                    }
21146                })
21147                .on_click({
21148                    let editor = editor.clone();
21149                    move |_event, _window, cx| {
21150                        editor.update(cx, |editor, cx| {
21151                            editor.stage_or_unstage_diff_hunks(
21152                                false,
21153                                vec![hunk_range.start..hunk_range.start],
21154                                cx,
21155                            );
21156                        });
21157                    }
21158                })
21159        })
21160        .child(
21161            Button::new(("restore", row as u64), "Restore")
21162                .tooltip({
21163                    let focus_handle = editor.focus_handle(cx);
21164                    move |window, cx| {
21165                        Tooltip::for_action_in(
21166                            "Restore Hunk",
21167                            &::git::Restore,
21168                            &focus_handle,
21169                            window,
21170                            cx,
21171                        )
21172                    }
21173                })
21174                .on_click({
21175                    let editor = editor.clone();
21176                    move |_event, window, cx| {
21177                        editor.update(cx, |editor, cx| {
21178                            let snapshot = editor.snapshot(window, cx);
21179                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21180                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21181                        });
21182                    }
21183                })
21184                .disabled(is_created_file),
21185        )
21186        .when(
21187            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21188            |el| {
21189                el.child(
21190                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21191                        .shape(IconButtonShape::Square)
21192                        .icon_size(IconSize::Small)
21193                        // .disabled(!has_multiple_hunks)
21194                        .tooltip({
21195                            let focus_handle = editor.focus_handle(cx);
21196                            move |window, cx| {
21197                                Tooltip::for_action_in(
21198                                    "Next Hunk",
21199                                    &GoToHunk,
21200                                    &focus_handle,
21201                                    window,
21202                                    cx,
21203                                )
21204                            }
21205                        })
21206                        .on_click({
21207                            let editor = editor.clone();
21208                            move |_event, window, cx| {
21209                                editor.update(cx, |editor, cx| {
21210                                    let snapshot = editor.snapshot(window, cx);
21211                                    let position =
21212                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21213                                    editor.go_to_hunk_before_or_after_position(
21214                                        &snapshot,
21215                                        position,
21216                                        Direction::Next,
21217                                        window,
21218                                        cx,
21219                                    );
21220                                    editor.expand_selected_diff_hunks(cx);
21221                                });
21222                            }
21223                        }),
21224                )
21225                .child(
21226                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21227                        .shape(IconButtonShape::Square)
21228                        .icon_size(IconSize::Small)
21229                        // .disabled(!has_multiple_hunks)
21230                        .tooltip({
21231                            let focus_handle = editor.focus_handle(cx);
21232                            move |window, cx| {
21233                                Tooltip::for_action_in(
21234                                    "Previous Hunk",
21235                                    &GoToPreviousHunk,
21236                                    &focus_handle,
21237                                    window,
21238                                    cx,
21239                                )
21240                            }
21241                        })
21242                        .on_click({
21243                            let editor = editor.clone();
21244                            move |_event, window, cx| {
21245                                editor.update(cx, |editor, cx| {
21246                                    let snapshot = editor.snapshot(window, cx);
21247                                    let point =
21248                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21249                                    editor.go_to_hunk_before_or_after_position(
21250                                        &snapshot,
21251                                        point,
21252                                        Direction::Prev,
21253                                        window,
21254                                        cx,
21255                                    );
21256                                    editor.expand_selected_diff_hunks(cx);
21257                                });
21258                            }
21259                        }),
21260                )
21261            },
21262        )
21263        .into_any_element()
21264}